/*-------------------------------------------------------------------------
 *
 * llvmjit_expr.c
 *	  JIT 编译表达式。
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
 *	  src/backend/jit/llvm/llvmjit_expr.c
 *
 *-------------------------------------------------------------------------
 */

#include "postgres.h"

#include <llvm-c/Core.h>
#include <llvm-c/Target.h>

#include "access/htup_details.h"
#include "access/nbtree.h"
#include "catalog/objectaccess.h"
#include "catalog/pg_type.h"
#include "executor/execExpr.h"
#include "executor/execdebug.h"
#include "executor/nodeAgg.h"
#include "executor/nodeSubplan.h"
#include "funcapi.h"
#include "jit/llvmjit.h"
#include "jit/llvmjit_emit.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "parser/parse_coerce.h"
#include "parser/parsetree.h"
#include "pgstat.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/date.h"
#include "utils/fmgrtab.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/timestamp.h"
#include "utils/typcache.h"
#include "utils/xml.h"

typedef struct CompiledExprState
{
	LLVMJitContext *context;
	const char *funcname;
} CompiledExprState;


static Datum fc_ExecRunCompiledExpr(ExprState *fc_state, ExprContext *fc_econtext, bool *fc_isNull);

static LLVMValueRef fc_BuildV1Call(LLVMJitContext *fc_context, LLVMBuilderRef fc_b,
								LLVMModuleRef fc_mod, FunctionCallInfo fcinfo,
								LLVMValueRef *fc_v_fcinfo_isnull);
static LLVMValueRef fc_build_EvalXFuncInt(LLVMBuilderRef fc_b, LLVMModuleRef fc_mod,
									   const char *fc_funcname,
									   LLVMValueRef fc_v_state,
									   ExprEvalStep *fc_op,
									   int fc_natts, LLVMValueRef *fc_v_args);
static LLVMValueRef fc_create_LifetimeEnd(LLVMModuleRef fc_mod);

/* 方便调用 ExecEval* 函数的宏 */
#define build_EvalXFunc(b, mod, funcname, v_state, op, ...) \
	fc_build_EvalXFuncInt(b, mod, funcname, v_state, op, \
					   lengthof(((LLVMValueRef[]){__VA_ARGS__})), \
					   ((LLVMValueRef[]){__VA_ARGS__}))


/*
 * JIT 编译表达式。
 */
bool llvm_compile_expr(ExprState *fc_state)
{
	PlanState  *fc_parent = fc_state->parent;
	char	   *fc_funcname;

	LLVMJitContext *fc_context = NULL;

	LLVMBuilderRef fc_b;
	LLVMModuleRef fc_mod;
	LLVMContextRef fc_lc;
	LLVMValueRef fc_eval_fn;
	LLVMBasicBlockRef fc_entry;
	LLVMBasicBlockRef *fc_opblocks;

	/* 自身状态 */
	LLVMValueRef fc_v_state;
	LLVMValueRef fc_v_econtext;
	LLVMValueRef fc_v_parent;

	/* 返回值 */
	LLVMValueRef fc_v_isnullp;

	/* 状态中的临时变量 */
	LLVMValueRef fc_v_tmpvaluep;
	LLVMValueRef fc_v_tmpisnullp;

	/* slots */
	LLVMValueRef fc_v_innerslot;
	LLVMValueRef fc_v_outerslot;
	LLVMValueRef fc_v_scanslot;
	LLVMValueRef fc_v_resultslot;

	/* 插槽的空值/值 */
	LLVMValueRef fc_v_innervalues;
	LLVMValueRef fc_v_innernulls;
	LLVMValueRef fc_v_outervalues;
	LLVMValueRef fc_v_outernulls;
	LLVMValueRef fc_v_scanvalues;
	LLVMValueRef fc_v_scannulls;
	LLVMValueRef fc_v_resultvalues;
	LLVMValueRef fc_v_resultnulls;

	/* econtext 中的内容 */
	LLVMValueRef fc_v_aggvalues;
	LLVMValueRef fc_v_aggnulls;

	instr_time	fc_starttime;
	instr_time	fc_endtime;

	llvm_enter_fatal_on_oom();

	/*
	 * 目前我们不支持编译没有父级的表达式，因为
	 * 我们需要访问 EState。
	 */
	Assert(fc_parent);

	/* 获取或创建 JIT 上下文 */
	if (fc_parent->state->es_jit)
		fc_context = (LLVMJitContext *) fc_parent->state->es_jit;
	else
	{
		fc_context = llvm_create_context(fc_parent->state->es_jit_flags);
		fc_parent->state->es_jit = &fc_context->base;
	}

	INSTR_TIME_SET_CURRENT(fc_starttime);

	fc_mod = llvm_mutable_module(fc_context);
	fc_lc = LLVMGetModuleContext(fc_mod);

	fc_b = LLVMCreateBuilderInContext(fc_lc);

	fc_funcname = llvm_expand_funcname(fc_context, "evalexpr");

	/* 创建函数 */
	fc_eval_fn = LLVMAddFunction(fc_mod, fc_funcname,
							  llvm_pg_var_func_type("ExecInterpExprStillValid"));
	LLVMSetLinkage(fc_eval_fn, LLVMExternalLinkage);
	LLVMSetVisibility(fc_eval_fn, LLVMDefaultVisibility);
	llvm_copy_attributes(AttributeTemplate, fc_eval_fn);

	fc_entry = LLVMAppendBasicBlockInContext(fc_lc, fc_eval_fn, "entry");

	/* 构建状态 */
	fc_v_state = LLVMGetParam(fc_eval_fn, 0);
	fc_v_econtext = LLVMGetParam(fc_eval_fn, 1);
	fc_v_isnullp = LLVMGetParam(fc_eval_fn, 2);

	LLVMPositionBuilderAtEnd(fc_b, fc_entry);

	fc_v_tmpvaluep = l_struct_gep(fc_b,
							   StructExprState,
							   fc_v_state,
							   FIELDNO_EXPRSTATE_RESVALUE,
							   "v.state.resvalue");
	fc_v_tmpisnullp = l_struct_gep(fc_b,
								StructExprState,
								fc_v_state,
								FIELDNO_EXPRSTATE_RESNULL,
								"v.state.resnull");
	fc_v_parent = l_load_struct_gep(fc_b,
								 StructExprState,
								 fc_v_state,
								 FIELDNO_EXPRSTATE_PARENT,
								 "v.state.parent");

	/* 构建全局插槽 */
	fc_v_scanslot = l_load_struct_gep(fc_b,
								   StructExprContext,
								   fc_v_econtext,
								   FIELDNO_EXPRCONTEXT_SCANTUPLE,
								   "v_scanslot");
	fc_v_innerslot = l_load_struct_gep(fc_b,
									StructExprContext,
									fc_v_econtext,
									FIELDNO_EXPRCONTEXT_INNERTUPLE,
									"v_innerslot");
	fc_v_outerslot = l_load_struct_gep(fc_b,
									StructExprContext,
									fc_v_econtext,
									FIELDNO_EXPRCONTEXT_OUTERTUPLE,
									"v_outerslot");
	fc_v_resultslot = l_load_struct_gep(fc_b,
									 StructExprState,
									 fc_v_state,
									 FIELDNO_EXPRSTATE_RESULTSLOT,
									 "v_resultslot");

	/* 构建全局值/isnull 指针 */
	fc_v_scanvalues = l_load_struct_gep(fc_b,
									 StructTupleTableSlot,
									 fc_v_scanslot,
									 FIELDNO_TUPLETABLESLOT_VALUES,
									 "v_scanvalues");
	fc_v_scannulls = l_load_struct_gep(fc_b,
									StructTupleTableSlot,
									fc_v_scanslot,
									FIELDNO_TUPLETABLESLOT_ISNULL,
									"v_scannulls");
	fc_v_innervalues = l_load_struct_gep(fc_b,
									  StructTupleTableSlot,
									  fc_v_innerslot,
									  FIELDNO_TUPLETABLESLOT_VALUES,
									  "v_innervalues");
	fc_v_innernulls = l_load_struct_gep(fc_b,
									 StructTupleTableSlot,
									 fc_v_innerslot,
									 FIELDNO_TUPLETABLESLOT_ISNULL,
									 "v_innernulls");
	fc_v_outervalues = l_load_struct_gep(fc_b,
									  StructTupleTableSlot,
									  fc_v_outerslot,
									  FIELDNO_TUPLETABLESLOT_VALUES,
									  "v_outervalues");
	fc_v_outernulls = l_load_struct_gep(fc_b,
									 StructTupleTableSlot,
									 fc_v_outerslot,
									 FIELDNO_TUPLETABLESLOT_ISNULL,
									 "v_outernulls");
	fc_v_resultvalues = l_load_struct_gep(fc_b,
									   StructTupleTableSlot,
									   fc_v_resultslot,
									   FIELDNO_TUPLETABLESLOT_VALUES,
									   "v_resultvalues");
	fc_v_resultnulls = l_load_struct_gep(fc_b,
									  StructTupleTableSlot,
									  fc_v_resultslot,
									  FIELDNO_TUPLETABLESLOT_ISNULL,
									  "v_resultnulls");

	/* aggvalues/aggnulls */
	fc_v_aggvalues = l_load_struct_gep(fc_b,
									StructExprContext,
									fc_v_econtext,
									FIELDNO_EXPRCONTEXT_AGGVALUES,
									"v.econtext.aggvalues");
	fc_v_aggnulls = l_load_struct_gep(fc_b,
								   StructExprContext,
								   fc_v_econtext,
								   FIELDNO_EXPRCONTEXT_AGGNULLS,
								   "v.econtext.aggnulls");

	/* 为每个操作预先分配块，以便我们可以轻松跳转 */
	fc_opblocks = palloc(sizeof(LLVMBasicBlockRef) * fc_state->steps_len);
	for (int fc_opno = 0; fc_opno < fc_state->steps_len; fc_opno++)
		fc_opblocks[fc_opno] = l_bb_append_v(fc_eval_fn, "b.op.%d.start", fc_opno);

	/* 从入口跳转到第一个块 */
	LLVMBuildBr(fc_b, fc_opblocks[0]);

	for (int fc_opno = 0; fc_opno < fc_state->steps_len; fc_opno++)
	{
		ExprEvalStep *fc_op;
		ExprEvalOp	fc_opcode;
		LLVMValueRef fc_v_resvaluep;
		LLVMValueRef fc_v_resnullp;

		LLVMPositionBuilderAtEnd(fc_b, fc_opblocks[fc_opno]);

		fc_op = &fc_state->steps[fc_opno];
		fc_opcode = ExecEvalStepOp(fc_state, fc_op);

		fc_v_resvaluep = l_ptr_const(fc_op->resvalue, l_ptr(TypeSizeT));
		fc_v_resnullp = l_ptr_const(fc_op->resnull, l_ptr(TypeStorageBool));

		switch (fc_opcode)
		{
			case EEOP_DONE:
				{
					LLVMValueRef fc_v_tmpisnull;
					LLVMValueRef fc_v_tmpvalue;

					fc_v_tmpvalue = l_load(fc_b, TypeSizeT, fc_v_tmpvaluep, "");
					fc_v_tmpisnull = l_load(fc_b, TypeStorageBool, fc_v_tmpisnullp, "");

					LLVMBuildStore(fc_b, fc_v_tmpisnull, fc_v_isnullp);

					LLVMBuildRet(fc_b, fc_v_tmpvalue);
					break;
				}

			case EEOP_INNER_FETCHSOME:
			case EEOP_OUTER_FETCHSOME:
			case EEOP_SCAN_FETCHSOME:
				{
					TupleDesc	fc_desc = NULL;
					LLVMValueRef fc_v_slot;
					LLVMBasicBlockRef fc_b_fetch;
					LLVMValueRef fc_v_nvalid;
					LLVMValueRef fc_l_jit_deform = NULL;
					const TupleTableSlotOps *fc_tts_ops = NULL;

					fc_b_fetch = l_bb_before_v(fc_opblocks[fc_opno + 1],
											"op.%d.fetch", fc_opno);

					if (fc_op->d.fetch.known_desc)
						fc_desc = fc_op->d.fetch.known_desc;

					if (fc_op->d.fetch.fixed)
						fc_tts_ops = fc_op->d.fetch.kind;

					/* 步骤不应该被生成 */
					Assert(fc_tts_ops != &TTSOpsVirtual);

					if (fc_opcode == EEOP_INNER_FETCHSOME)
						fc_v_slot = fc_v_innerslot;
					else if (fc_opcode == EEOP_OUTER_FETCHSOME)
						fc_v_slot = fc_v_outerslot;
					else
						fc_v_slot = fc_v_scanslot;

					/*
					 * 检查所有所需属性是否可用，或者
					 * 是否需要变形。
					 */
					fc_v_nvalid =
						l_load_struct_gep(fc_b,
										  StructTupleTableSlot,
										  fc_v_slot,
										  FIELDNO_TUPLETABLESLOT_NVALID,
										  "");
					LLVMBuildCondBr(fc_b,
									LLVMBuildICmp(fc_b, LLVMIntUGE, fc_v_nvalid,
												  l_int16_const(fc_lc, fc_op->d.fetch.last_var),
												  ""),
									fc_opblocks[fc_opno + 1], fc_b_fetch);

					LLVMPositionBuilderAtEnd(fc_b, fc_b_fetch);

					/*
					 * 如果待变形元组的元组描述已知，
					 * 并且启用了变形的 JIT，则构建特定于元组描述的
					 * 变形函数以及待提取的属性的确切数量。
					 */
					if (fc_tts_ops && fc_desc && (fc_context->base.flags & PGJIT_DEFORM))
					{
						fc_l_jit_deform =
							slot_compile_deform(fc_context, fc_desc,
												fc_tts_ops,
												fc_op->d.fetch.last_var);
					}

					if (fc_l_jit_deform)
					{
						LLVMValueRef fc_params[1];

						fc_params[0] = fc_v_slot;

						l_call(fc_b,
							   LLVMGetFunctionType(fc_l_jit_deform),
							   fc_l_jit_deform,
							   fc_params, lengthof(fc_params), "");
					}
					else
					{
						LLVMValueRef fc_params[2];

						fc_params[0] = fc_v_slot;
						fc_params[1] = l_int32_const(fc_lc, fc_op->d.fetch.last_var);

						l_call(fc_b,
							   llvm_pg_var_func_type("slot_getsomeattrs_int"),
							   llvm_pg_func(fc_mod, "slot_getsomeattrs_int"),
							   fc_params, lengthof(fc_params), "");
					}

					LLVMBuildBr(fc_b, fc_opblocks[fc_opno + 1]);
					break;
				}

			case EEOP_INNER_VAR:
			case EEOP_OUTER_VAR:
			case EEOP_SCAN_VAR:
				{
					LLVMValueRef fc_value,
								fc_isnull;
					LLVMValueRef fc_v_attnum;
					LLVMValueRef fc_v_values;
					LLVMValueRef fc_v_nulls;

					if (fc_opcode == EEOP_INNER_VAR)
					{
						fc_v_values = fc_v_innervalues;
						fc_v_nulls = fc_v_innernulls;
					}
					else if (fc_opcode == EEOP_OUTER_VAR)
					{
						fc_v_values = fc_v_outervalues;
						fc_v_nulls = fc_v_outernulls;
					}
					else
					{
						fc_v_values = fc_v_scanvalues;
						fc_v_nulls = fc_v_scannulls;
					}

					fc_v_attnum = l_int32_const(fc_lc, fc_op->d.var.attnum);
					fc_value = l_load_gep1(fc_b, TypeSizeT, fc_v_values, fc_v_attnum, "");
					fc_isnull = l_load_gep1(fc_b, TypeStorageBool, fc_v_nulls, fc_v_attnum, "");
					LLVMBuildStore(fc_b, fc_value, fc_v_resvaluep);
					LLVMBuildStore(fc_b, fc_isnull, fc_v_resnullp);

					LLVMBuildBr(fc_b, fc_opblocks[fc_opno + 1]);
					break;
				}

			case EEOP_INNER_SYSVAR:
			case EEOP_OUTER_SYSVAR:
			case EEOP_SCAN_SYSVAR:
				{
					LLVMValueRef fc_v_slot;

					if (fc_opcode == EEOP_INNER_SYSVAR)
						fc_v_slot = fc_v_innerslot;
					else if (fc_opcode == EEOP_OUTER_SYSVAR)
						fc_v_slot = fc_v_outerslot;
					else
						fc_v_slot = fc_v_scanslot;

					build_EvalXFunc(fc_b, fc_mod, "ExecEvalSysVar",
									fc_v_state, fc_op, fc_v_econtext, fc_v_slot);

					LLVMBuildBr(fc_b, fc_opblocks[fc_opno + 1]);
					break;
				}

			case EEOP_WHOLEROW:
				build_EvalXFunc(fc_b, fc_mod, "ExecEvalWholeRowVar",
								fc_v_state, fc_op, fc_v_econtext);
				LLVMBuildBr(fc_b, fc_opblocks[fc_opno + 1]);
				break;

			case EEOP_ASSIGN_INNER_VAR:
			case EEOP_ASSIGN_OUTER_VAR:
			case EEOP_ASSIGN_SCAN_VAR:
				{
					LLVMValueRef fc_v_value;
					LLVMValueRef fc_v_isnull;
					LLVMValueRef fc_v_rvaluep;
					LLVMValueRef fc_v_risnullp;
					LLVMValueRef fc_v_attnum;
					LLVMValueRef fc_v_resultnum;
					LLVMValueRef fc_v_values;
					LLVMValueRef fc_v_nulls;

					if (fc_opcode == EEOP_ASSIGN_INNER_VAR)
					{
						fc_v_values = fc_v_innervalues;
						fc_v_nulls = fc_v_innernulls;
					}
					else if (fc_opcode == EEOP_ASSIGN_OUTER_VAR)
					{
						fc_v_values = fc_v_outervalues;
						fc_v_nulls = fc_v_outernulls;
					}
					else
					{
						fc_v_values = fc_v_scanvalues;
						fc_v_nulls = fc_v_scannulls;
					}

					/* 加载数据 */
					fc_v_attnum = l_int32_const(fc_lc, fc_op->d.assign_var.attnum);
					fc_v_value = l_load_gep1(fc_b, TypeSizeT, fc_v_values, fc_v_attnum, "");
					fc_v_isnull = l_load_gep1(fc_b, TypeStorageBool, fc_v_nulls, fc_v_attnum, "");

					/* 计算目标的地址 */
					fc_v_resultnum = l_int32_const(fc_lc, fc_op->d.assign_var.resultnum);
					fc_v_rvaluep = l_gep(fc_b,
									  TypeSizeT,
									  fc_v_resultvalues,
									  &fc_v_resultnum, 1, "");
					fc_v_risnullp = l_gep(fc_b,
									   TypeStorageBool,
									   fc_v_resultnulls,
									   &fc_v_resultnum, 1, "");

					/* 并存储 */
					LLVMBuildStore(fc_b, fc_v_value, fc_v_rvaluep);
					LLVMBuildStore(fc_b, fc_v_isnull, fc_v_risnullp);

					LLVMBuildBr(fc_b, fc_opblocks[fc_opno + 1]);
					break;
				}

			case EEOP_ASSIGN_TMP:
			case EEOP_ASSIGN_TMP_MAKE_RO:
				{
					LLVMValueRef fc_v_value,
								fc_v_isnull;
					LLVMValueRef fc_v_rvaluep,
								fc_v_risnullp;
					LLVMValueRef fc_v_resultnum;
					size_t		fc_resultnum = fc_op->d.assign_tmp.resultnum;

					/* 加载数据 */
					fc_v_value = l_load(fc_b, TypeSizeT, fc_v_tmpvaluep, "");
					fc_v_isnull = l_load(fc_b, TypeStorageBool, fc_v_tmpisnullp, "");

					/* 计算目标的地址 */
					fc_v_resultnum = l_int32_const(fc_lc, fc_resultnum);
					fc_v_rvaluep =
						l_gep(fc_b, TypeSizeT, fc_v_resultvalues, &fc_v_resultnum, 1, "");
					fc_v_risnullp =
						l_gep(fc_b, TypeStorageBool, fc_v_resultnulls, &fc_v_resultnum, 1, "");

					/* 存储空值性 */
					LLVMBuildStore(fc_b, fc_v_isnull, fc_v_risnullp);

					/* 如果必要，使值只读 */
					if (fc_opcode == EEOP_ASSIGN_TMP_MAKE_RO)
					{
						LLVMBasicBlockRef fc_b_notnull;
						LLVMValueRef fc_v_params[1];

						fc_b_notnull = l_bb_before_v(fc_opblocks[fc_opno + 1],
												  "op.%d.assign_tmp.notnull", fc_opno);

						/* 检查值是否为 NULL */
						LLVMBuildCondBr(fc_b,
										LLVMBuildICmp(fc_b, LLVMIntEQ, fc_v_isnull,
													  l_sbool_const(0), ""),
										fc_b_notnull, fc_opblocks[fc_opno + 1]);

						/* 如果值不为 null，将其转换为只读数据 */
						LLVMPositionBuilderAtEnd(fc_b, fc_b_notnull);
						fc_v_params[0] = fc_v_value;
						fc_v_value =
							l_call(fc_b,
								   llvm_pg_var_func_type("MakeExpandedObjectReadOnlyInternal"),
								   llvm_pg_func(fc_mod, "MakeExpandedObjectReadOnlyInternal"),
								   fc_v_params, lengthof(fc_v_params), "");

						/*
						 * 从 if () 退出，构建器在 b_notnull 中，
						 * 这很好 - 空值已经在上面存储。
						 */
					}

					/* 最后存储结果 */
					LLVMBuildStore(fc_b, fc_v_value, fc_v_rvaluep);

					LLVMBuildBr(fc_b, fc_opblocks[fc_opno + 1]);
					break;
				}

			case EEOP_CONST:
				{
					LLVMValueRef fc_v_constvalue,
								fc_v_constnull;

					fc_v_constvalue = l_sizet_const(fc_op->d.constval.value);
					fc_v_constnull = l_sbool_const(fc_op->d.constval.isnull);

					LLVMBuildStore(fc_b, fc_v_constvalue, fc_v_resvaluep);
					LLVMBuildStore(fc_b, fc_v_constnull, fc_v_resnullp);

					LLVMBuildBr(fc_b, fc_opblocks[fc_opno + 1]);
					break;
				}

			case EEOP_FUNCEXPR:
			case EEOP_FUNCEXPR_STRICT:
				{
					FunctionCallInfo fcinfo = fc_op->d.func.fcinfo_data;
					LLVMValueRef fc_v_fcinfo_isnull;
					LLVMValueRef fc_v_retval;

					if (fc_opcode == EEOP_FUNCEXPR_STRICT)
					{
						LLVMBasicBlockRef fc_b_nonull;
						LLVMBasicBlockRef *fc_b_checkargnulls;
						LLVMValueRef fc_v_fcinfo;

						/*
						 * 实际函数调用的块，如果参数为
						 * 非空。
						 */
						fc_b_nonull = l_bb_before_v(fc_opblocks[fc_opno + 1],
												 "b.%d.no-null-args", fc_opno);

						/* 应该确保它们提前优化 */
						if (fc_op->d.func.nargs == 0)
							elog(ERROR, "argumentless strict functions are pointless");

						fc_v_fcinfo =
							l_ptr_const(fcinfo, l_ptr(StructFunctionCallInfoData));

						/*
						 * 如果函数实际上被调用，则将 resnull 设置为 true，它会被重置
						 */
						LLVMBuildStore(fc_b, l_sbool_const(1), fc_v_resnullp);

						/* 创建用于检查参数的块，每个参数一个 */
						fc_b_checkargnulls =
							palloc(sizeof(LLVMBasicBlockRef *) * fc_op->d.func.nargs);
						for (int fc_argno = 0; fc_argno < fc_op->d.func.nargs; fc_argno++)
							fc_b_checkargnulls[fc_argno] =
								l_bb_before_v(fc_b_nonull, "b.%d.isnull.%d", fc_opno,
											  fc_argno);

						/* 跳转到检查第一个参数 */
						LLVMBuildBr(fc_b, fc_b_checkargnulls[0]);

						/* 检查每个参数的空值性 */
						for (int fc_argno = 0; fc_argno < fc_op->d.func.nargs; fc_argno++)
						{
							LLVMValueRef fc_v_argisnull;
							LLVMBasicBlockRef fc_b_argnotnull;

							LLVMPositionBuilderAtEnd(fc_b, fc_b_checkargnulls[fc_argno]);

							/*
							 * 计算如果参数不为
							 * null 的跳转块。
							 */
							if (fc_argno + 1 == fc_op->d.func.nargs)
								fc_b_argnotnull = fc_b_nonull;
							else
								fc_b_argnotnull = fc_b_checkargnulls[fc_argno + 1];

							/* 最后加载并检查参数的空值性 */
							fc_v_argisnull = l_funcnull(fc_b, fc_v_fcinfo, fc_argno);
							LLVMBuildCondBr(fc_b,
											LLVMBuildICmp(fc_b, LLVMIntEQ,
														  fc_v_argisnull,
														  l_sbool_const(1),
														  ""),
											fc_opblocks[fc_opno + 1],
											fc_b_argnotnull);
						}

						LLVMPositionBuilderAtEnd(fc_b, fc_b_nonull);
					}

					fc_v_retval = fc_BuildV1Call(fc_context, fc_b, fc_mod, fcinfo,
										   &fc_v_fcinfo_isnull);
					LLVMBuildStore(fc_b, fc_v_retval, fc_v_resvaluep);
					LLVMBuildStore(fc_b, fc_v_fcinfo_isnull, fc_v_resnullp);

					LLVMBuildBr(fc_b, fc_opblocks[fc_opno + 1]);
					break;
				}

			case EEOP_FUNCEXPR_FUSAGE:
				build_EvalXFunc(fc_b, fc_mod, "ExecEvalFuncExprFusage",
								fc_v_state, fc_op, fc_v_econtext);
				LLVMBuildBr(fc_b, fc_opblocks[fc_opno + 1]);
				break;


			case EEOP_FUNCEXPR_STRICT_FUSAGE:
				build_EvalXFunc(fc_b, fc_mod, "ExecEvalFuncExprStrictFusage",
								fc_v_state, fc_op, fc_v_econtext);
				LLVMBuildBr(fc_b, fc_opblocks[fc_opno + 1]);
				break;

				/*
				 * 现在将它们视为相同，优化器可以去除
				 * 冗余。不过在发射期间优化可能是值得的。
				 */
			case EEOP_BOOL_AND_STEP_FIRST:
			case EEOP_BOOL_AND_STEP:
			case EEOP_BOOL_AND_STEP_LAST:
				{
					LLVMValueRef fc_v_boolvalue;
					LLVMValueRef fc_v_boolnull;
					LLVMValueRef fc_v_boolanynullp,
								fc_v_boolanynull;
					LLVMBasicBlockRef fc_b_boolisnull;
					LLVMBasicBlockRef fc_b_boolcheckfalse;
					LLVMBasicBlockRef fc_b_boolisfalse;
					LLVMBasicBlockRef fc_b_boolcont;
					LLVMBasicBlockRef fc_b_boolisanynull;

					fc_b_boolisnull = l_bb_before_v(fc_opblocks[fc_opno + 1],
												 "b.%d.boolisnull", fc_opno);
					fc_b_boolcheckfalse = l_bb_before_v(fc_opblocks[fc_opno + 1],
													 "b.%d.boolcheckfalse", fc_opno);
					fc_b_boolisfalse = l_bb_before_v(fc_opblocks[fc_opno + 1],
												  "b.%d.boolisfalse", fc_opno);
					fc_b_boolisanynull = l_bb_before_v(fc_opblocks[fc_opno + 1],
													"b.%d.boolisanynull", fc_opno);
					fc_b_boolcont = l_bb_before_v(fc_opblocks[fc_opno + 1],
											   "b.%d.boolcont", fc_opno);

					fc_v_boolanynullp = l_ptr_const(fc_op->d.boolexpr.anynull,
												 l_ptr(TypeStorageBool));

					if (fc_opcode == EEOP_BOOL_AND_STEP_FIRST)
						LLVMBuildStore(fc_b, l_sbool_const(0), fc_v_boolanynullp);

					fc_v_boolnull = l_load(fc_b, TypeStorageBool, fc_v_resnullp, "");
					fc_v_boolvalue = l_load(fc_b, TypeSizeT, fc_v_resvaluep, "");

					/* 将 resnull 设置为 boolnull */
					LLVMBuildStore(fc_b, fc_v_boolnull, fc_v_resnullp);
					/* 将 revalue 设置为 boolvalue */
					LLVMBuildStore(fc_b, fc_v_boolvalue, fc_v_resvaluep);

					/* 检查当前输入是否为 NULL */
					LLVMBuildCondBr(fc_b,
									LLVMBuildICmp(fc_b, LLVMIntEQ, fc_v_boolnull,
												  l_sbool_const(1), ""),
									fc_b_boolisnull,
									fc_b_boolcheckfalse);

					/* 构建设置 anynull 的块 */
					LLVMPositionBuilderAtEnd(fc_b, fc_b_boolisnull);
					/* 将 boolanynull 设置为 true */
					LLVMBuildStore(fc_b, l_sbool_const(1), fc_v_boolanynullp);
					/* 并跳转到下一个块 */
					LLVMBuildBr(fc_b, fc_b_boolcont);

					/* 构建检查假值的块 */
					LLVMPositionBuilderAtEnd(fc_b, fc_b_boolcheckfalse);
					LLVMBuildCondBr(fc_b,
									LLVMBuildICmp(fc_b, LLVMIntEQ, fc_v_boolvalue,
												  l_sizet_const(0), ""),
									fc_b_boolisfalse,
									fc_b_boolcont);

					/*
					 * 构建处理假值的块。值为假，因此短路。
					 */
					LLVMPositionBuilderAtEnd(fc_b, fc_b_boolisfalse);
					/* 结果已经设置为 FALSE，不需要更改它 */
					/* 并跳转到 AND 表达式的末尾 */
					LLVMBuildBr(fc_b, fc_opblocks[fc_op->d.boolexpr.jumpdone]);

					/* 构建继续的块，如果布尔值为真。 */
					LLVMPositionBuilderAtEnd(fc_b, fc_b_boolcont);

					fc_v_boolanynull = l_load(fc_b, TypeStorageBool, fc_v_boolanynullp, "");

					/* 如果之前的任何值为 NULL，则将值设置为 NULL */
					LLVMBuildCondBr(fc_b,
									LLVMBuildICmp(fc_b, LLVMIntEQ, fc_v_boolanynull,
												  l_sbool_const(0), ""),
									fc_opblocks[fc_opno + 1], fc_b_boolisanynull);

					LLVMPositionBuilderAtEnd(fc_b, fc_b_boolisanynull);
					/* 将 resnull 设置为 true */
					LLVMBuildStore(fc_b, l_sbool_const(1), fc_v_resnullp);
					/* 重置 resvalue */
					LLVMBuildStore(fc_b, l_sizet_const(0), fc_v_resvaluep);

					LLVMBuildBr(fc_b, fc_opblocks[fc_opno + 1]);
					break;
				}

				/*
				 * 现在将它们视为相同，优化器可以去除
				 * 冗余。不过在发射期间优化可能是值得的。
				 */
			case EEOP_BOOL_OR_STEP_FIRST:
			case EEOP_BOOL_OR_STEP:
			case EEOP_BOOL_OR_STEP_LAST:
				{
					LLVMValueRef fc_v_boolvalue;
					LLVMValueRef fc_v_boolnull;
					LLVMValueRef fc_v_boolanynullp,
								fc_v_boolanynull;

					LLVMBasicBlockRef fc_b_boolisnull;
					LLVMBasicBlockRef fc_b_boolchecktrue;
					LLVMBasicBlockRef fc_b_boolistrue;
					LLVMBasicBlockRef fc_b_boolcont;
					LLVMBasicBlockRef fc_b_boolisanynull;

					fc_b_boolisnull = l_bb_before_v(fc_opblocks[fc_opno + 1],
												 "b.%d.boolisnull", fc_opno);
					fc_b_boolchecktrue = l_bb_before_v(fc_opblocks[fc_opno + 1],
													"b.%d.boolchecktrue", fc_opno);
					fc_b_boolistrue = l_bb_before_v(fc_opblocks[fc_opno + 1],
												 "b.%d.boolistrue", fc_opno);
					fc_b_boolisanynull = l_bb_before_v(fc_opblocks[fc_opno + 1],
													"b.%d.boolisanynull", fc_opno);
					fc_b_boolcont = l_bb_before_v(fc_opblocks[fc_opno + 1],
											   "b.%d.boolcont", fc_opno);

					fc_v_boolanynullp = l_ptr_const(fc_op->d.boolexpr.anynull,
												 l_ptr(TypeStorageBool));

					if (fc_opcode == EEOP_BOOL_OR_STEP_FIRST)
						LLVMBuildStore(fc_b, l_sbool_const(0), fc_v_boolanynullp);
					fc_v_boolnull = l_load(fc_b, TypeStorageBool, fc_v_resnullp, "");
					fc_v_boolvalue = l_load(fc_b, TypeSizeT, fc_v_resvaluep, "");

					/* 将 resnull 设置为 boolnull */
					LLVMBuildStore(fc_b, fc_v_boolnull, fc_v_resnullp);
					/* 将 revalue 设置为 boolvalue */
					LLVMBuildStore(fc_b, fc_v_boolvalue, fc_v_resvaluep);

					LLVMBuildCondBr(fc_b,
									LLVMBuildICmp(fc_b, LLVMIntEQ, fc_v_boolnull,
												  l_sbool_const(1), ""),
									fc_b_boolisnull,
									fc_b_boolchecktrue);

					/* 构建设置 anynull 的块 */
					LLVMPositionBuilderAtEnd(fc_b, fc_b_boolisnull);
					/* 将 boolanynull 设置为 true */
					LLVMBuildStore(fc_b, l_sbool_const(1), fc_v_boolanynullp);
					/* 并跳转到下一个块 */
					LLVMBuildBr(fc_b, fc_b_boolcont);

					/* 构建检查真值的块 */
					LLVMPositionBuilderAtEnd(fc_b, fc_b_boolchecktrue);
					LLVMBuildCondBr(fc_b,
									LLVMBuildICmp(fc_b, LLVMIntEQ, fc_v_boolvalue,
												  l_sizet_const(1), ""),
									fc_b_boolistrue,
									fc_b_boolcont);

					/*
					 * 构建处理真值的块。值为真，因此短路。
					 */
					LLVMPositionBuilderAtEnd(fc_b, fc_b_boolistrue);
					/* 结果已经设置为 TRUE，不需要更改它 */
					/* 并跳转到 OR 表达式的末尾 */
					LLVMBuildBr(fc_b, fc_opblocks[fc_op->d.boolexpr.jumpdone]);

					/* 构建继续的块，如果布尔值为假 */
					LLVMPositionBuilderAtEnd(fc_b, fc_b_boolcont);

					fc_v_boolanynull = l_load(fc_b, TypeStorageBool, fc_v_boolanynullp, "");

					/* 如果之前的任何值为 NULL，则将值设置为 NULL */
					LLVMBuildCondBr(fc_b,
									LLVMBuildICmp(fc_b, LLVMIntEQ, fc_v_boolanynull,
												  l_sbool_const(0), ""),
									fc_opblocks[fc_opno + 1], fc_b_boolisanynull);

					LLVMPositionBuilderAtEnd(fc_b, fc_b_boolisanynull);
					/* 将 resnull 设置为 true */
					LLVMBuildStore(fc_b, l_sbool_const(1), fc_v_resnullp);
					/* 重置 resvalue */
					LLVMBuildStore(fc_b, l_sizet_const(0), fc_v_resvaluep);

					LLVMBuildBr(fc_b, fc_opblocks[fc_opno + 1]);
					break;
				}

			case EEOP_BOOL_NOT_STEP:
				{
					LLVMValueRef fc_v_boolvalue;
					LLVMValueRef fc_v_boolnull;
					LLVMValueRef fc_v_negbool;

					fc_v_boolnull = l_load(fc_b, TypeStorageBool, fc_v_resnullp, "");
					fc_v_boolvalue = l_load(fc_b, TypeSizeT, fc_v_resvaluep, "");

					fc_v_negbool = LLVMBuildZExt(fc_b,
											  LLVMBuildICmp(fc_b, LLVMIntEQ,
															fc_v_boolvalue,
															l_sizet_const(0),
															""),
											  TypeSizeT, "");
					/* 将 resnull 设置为 boolnull */
					LLVMBuildStore(fc_b, fc_v_boolnull, fc_v_resnullp);
					/* 将 revalue 设置为 !boolvalue */
					LLVMBuildStore(fc_b, fc_v_negbool, fc_v_resvaluep);

					LLVMBuildBr(fc_b, fc_opblocks[fc_opno + 1]);
					break;
				}

			case EEOP_QUAL:
				{
					LLVMValueRef fc_v_resnull;
					LLVMValueRef fc_v_resvalue;
					LLVMValueRef fc_v_nullorfalse;
					LLVMBasicBlockRef fc_b_qualfail;

					fc_b_qualfail = l_bb_before_v(fc_opblocks[fc_opno + 1],
											   "op.%d.qualfail", fc_opno);

					fc_v_resvalue = l_load(fc_b, TypeSizeT, fc_v_resvaluep, "");
					fc_v_resnull = l_load(fc_b, TypeStorageBool, fc_v_resnullp, "");

					fc_v_nullorfalse =
						LLVMBuildOr(fc_b,
									LLVMBuildICmp(fc_b, LLVMIntEQ, fc_v_resnull,
												  l_sbool_const(1), ""),
									LLVMBuildICmp(fc_b, LLVMIntEQ, fc_v_resvalue,
												  l_sizet_const(0), ""),
									"");

					LLVMBuildCondBr(fc_b,
									fc_v_nullorfalse,
									fc_b_qualfail,
									fc_opblocks[fc_opno + 1]);

					/* 构建处理 NULL 或假值的块 */
					LLVMPositionBuilderAtEnd(fc_b, fc_b_qualfail);
					/* 将 resnull 设置为假 */
					LLVMBuildStore(fc_b, l_sbool_const(0), fc_v_resnullp);
					/* 将 resvalue 设置为假 */
					LLVMBuildStore(fc_b, l_sizet_const(0), fc_v_resvaluep);
					/* 并跳出来 */
					LLVMBuildBr(fc_b, fc_opblocks[fc_op->d.qualexpr.jumpdone]);
					break;
				}

			case EEOP_JUMP:
				{
					LLVMBuildBr(fc_b, fc_opblocks[fc_op->d.jump.jumpdone]);
					break;
				}

			case EEOP_JUMP_IF_NULL:
				{
					LLVMValueRef fc_v_resnull;

					/* 如果当前结果为 null，则转移控制 */

					fc_v_resnull = l_load(fc_b, TypeStorageBool, fc_v_resnullp, "");

					LLVMBuildCondBr(fc_b,
									LLVMBuildICmp(fc_b, LLVMIntEQ, fc_v_resnull,
												  l_sbool_const(1), ""),
									fc_opblocks[fc_op->d.jump.jumpdone],
									fc_opblocks[fc_opno + 1]);
					break;
				}

			case EEOP_JUMP_IF_NOT_NULL:
				{
					LLVMValueRef fc_v_resnull;

					/* 如果当前结果为非空，则转移控制 */

					fc_v_resnull = l_load(fc_b, TypeStorageBool, fc_v_resnullp, "");

					LLVMBuildCondBr(fc_b,
									LLVMBuildICmp(fc_b, LLVMIntEQ, fc_v_resnull,
												  l_sbool_const(0), ""),
									fc_opblocks[fc_op->d.jump.jumpdone],
									fc_opblocks[fc_opno + 1]);
					break;
				}


			case EEOP_JUMP_IF_NOT_TRUE:
				{
					LLVMValueRef fc_v_resnull;
					LLVMValueRef fc_v_resvalue;
					LLVMValueRef fc_v_nullorfalse;

					/* 如果当前结果为 null 或 false，则转移控制 */

					fc_v_resvalue = l_load(fc_b, TypeSizeT, fc_v_resvaluep, "");
					fc_v_resnull = l_load(fc_b, TypeStorageBool, fc_v_resnullp, "");

					fc_v_nullorfalse =
						LLVMBuildOr(fc_b,
									LLVMBuildICmp(fc_b, LLVMIntEQ, fc_v_resnull,
												  l_sbool_const(1), ""),
									LLVMBuildICmp(fc_b, LLVMIntEQ, fc_v_resvalue,
												  l_sizet_const(0), ""),
									"");

					LLVMBuildCondBr(fc_b,
									fc_v_nullorfalse,
									fc_opblocks[fc_op->d.jump.jumpdone],
									fc_opblocks[fc_opno + 1]);
					break;
				}

			case EEOP_NULLTEST_ISNULL:
				{
					LLVMValueRef fc_v_resnull = l_load(fc_b, TypeStorageBool, fc_v_resnullp, "");
					LLVMValueRef fc_v_resvalue;

					fc_v_resvalue =
						LLVMBuildSelect(fc_b,
										LLVMBuildICmp(fc_b, LLVMIntEQ, fc_v_resnull,
													  l_sbool_const(1), ""),
										l_sizet_const(1),
										l_sizet_const(0),
										"");
					LLVMBuildStore(fc_b, fc_v_resvalue, fc_v_resvaluep);
					LLVMBuildStore(fc_b, l_sbool_const(0), fc_v_resnullp);

					LLVMBuildBr(fc_b, fc_opblocks[fc_opno + 1]);
					break;
				}

			case EEOP_NULLTEST_ISNOTNULL:
				{
					LLVMValueRef fc_v_resnull = l_load(fc_b, TypeStorageBool, fc_v_resnullp, "");
					LLVMValueRef fc_v_resvalue;

					fc_v_resvalue =
						LLVMBuildSelect(fc_b,
										LLVMBuildICmp(fc_b, LLVMIntEQ, fc_v_resnull,
													  l_sbool_const(1), ""),
										l_sizet_const(0),
										l_sizet_const(1),
										"");
					LLVMBuildStore(fc_b, fc_v_resvalue, fc_v_resvaluep);
					LLVMBuildStore(fc_b, l_sbool_const(0), fc_v_resnullp);

					LLVMBuildBr(fc_b, fc_opblocks[fc_opno + 1]);
					break;
				}

			case EEOP_NULLTEST_ROWISNULL:
				build_EvalXFunc(fc_b, fc_mod, "ExecEvalRowNull",
								fc_v_state, fc_op, fc_v_econtext);
				LLVMBuildBr(fc_b, fc_opblocks[fc_opno + 1]);
				break;

			case EEOP_NULLTEST_ROWISNOTNULL:
				build_EvalXFunc(fc_b, fc_mod, "ExecEvalRowNotNull",
								fc_v_state, fc_op, fc_v_econtext);
				LLVMBuildBr(fc_b, fc_opblocks[fc_opno + 1]);
				break;

			case EEOP_BOOLTEST_IS_TRUE:
			case EEOP_BOOLTEST_IS_NOT_FALSE:
			case EEOP_BOOLTEST_IS_FALSE:
			case EEOP_BOOLTEST_IS_NOT_TRUE:
				{
					LLVMBasicBlockRef fc_b_isnull,
								fc_b_notnull;
					LLVMValueRef fc_v_resnull = l_load(fc_b, TypeStorageBool, fc_v_resnullp, "");

					fc_b_isnull = l_bb_before_v(fc_opblocks[fc_opno + 1],
											 "op.%d.isnull", fc_opno);
					fc_b_notnull = l_bb_before_v(fc_opblocks[fc_opno + 1],
											  "op.%d.isnotnull", fc_opno);

					/* 检查值是否为 NULL */
					LLVMBuildCondBr(fc_b,
									LLVMBuildICmp(fc_b, LLVMIntEQ, fc_v_resnull,
												  l_sbool_const(1), ""),
									fc_b_isnull, fc_b_notnull);

					/* 如果值为 NULL，则返回假 */
					LLVMPositionBuilderAtEnd(fc_b, fc_b_isnull);

					/* 结果不是 null */
					LLVMBuildStore(fc_b, l_sbool_const(0), fc_v_resnullp);

					if (fc_opcode == EEOP_BOOLTEST_IS_TRUE ||
						fc_opcode == EEOP_BOOLTEST_IS_FALSE)
					{
						LLVMBuildStore(fc_b, l_sizet_const(0), fc_v_resvaluep);
					}
					else
					{
						LLVMBuildStore(fc_b, l_sizet_const(1), fc_v_resvaluep);
					}

					LLVMBuildBr(fc_b, fc_opblocks[fc_opno + 1]);

					LLVMPositionBuilderAtEnd(fc_b, fc_b_notnull);

					if (fc_opcode == EEOP_BOOLTEST_IS_TRUE ||
						fc_opcode == EEOP_BOOLTEST_IS_NOT_FALSE)
					{
						/*
						 * 如果值不是 null NULL，返回值（已经
						 * 设置）
						 */
					}
					else
					{
						LLVMValueRef fc_v_value =
							l_load(fc_b, TypeSizeT, fc_v_resvaluep, "");

						fc_v_value = LLVMBuildZExt(fc_b,
												LLVMBuildICmp(fc_b, LLVMIntEQ,
															  fc_v_value,
															  l_sizet_const(0),
															  ""),
												TypeSizeT, "");
						LLVMBuildStore(fc_b, fc_v_value, fc_v_resvaluep);
					}
					LLVMBuildBr(fc_b, fc_opblocks[fc_opno + 1]);
					break;
				}

			case EEOP_PARAM_EXEC:
				build_EvalXFunc(fc_b, fc_mod, "ExecEvalParamExec",
								fc_v_state, fc_op, fc_v_econtext);
				LLVMBuildBr(fc_b, fc_opblocks[fc_opno + 1]);
				break;

			case EEOP_PARAM_EXTERN:
				build_EvalXFunc(fc_b, fc_mod, "ExecEvalParamExtern",
								fc_v_state, fc_op, fc_v_econtext);
				LLVMBuildBr(fc_b, fc_opblocks[fc_opno + 1]);
				break;

			case EEOP_PARAM_CALLBACK:
				{
					LLVMValueRef fc_v_func;
					LLVMValueRef fc_v_params[3];

					fc_v_func = l_ptr_const(fc_op->d.cparam.paramfunc,
										 llvm_pg_var_type("TypeExecEvalSubroutine"));

					fc_v_params[0] = fc_v_state;
					fc_v_params[1] = l_ptr_const(fc_op, l_ptr(StructExprEvalStep));
					fc_v_params[2] = fc_v_econtext;
					l_call(fc_b,
						   LLVMGetFunctionType(ExecEvalSubroutineTemplate),
						   fc_v_func,
						   fc_v_params, lengthof(fc_v_params), "");

					LLVMBuildBr(fc_b, fc_opblocks[fc_opno + 1]);
					break;
				}

			case EEOP_SBSREF_SUBSCRIPTS:
				{
					int			fc_jumpdone = fc_op->d.sbsref_subscript.jumpdone;
					LLVMValueRef fc_v_func;
					LLVMValueRef fc_v_params[3];
					LLVMValueRef fc_v_ret;

					fc_v_func = l_ptr_const(fc_op->d.sbsref_subscript.subscriptfunc,
										 llvm_pg_var_type("TypeExecEvalBoolSubroutine"));

					fc_v_params[0] = fc_v_state;
					fc_v_params[1] = l_ptr_const(fc_op, l_ptr(StructExprEvalStep));
					fc_v_params[2] = fc_v_econtext;
					fc_v_ret = l_call(fc_b,
								   LLVMGetFunctionType(ExecEvalBoolSubroutineTemplate),
								   fc_v_func,
								   fc_v_params, lengthof(fc_v_params), "");
					fc_v_ret = LLVMBuildZExt(fc_b, fc_v_ret, TypeStorageBool, "");

					LLVMBuildCondBr(fc_b,
									LLVMBuildICmp(fc_b, LLVMIntEQ, fc_v_ret,
												  l_sbool_const(1), ""),
									fc_opblocks[fc_opno + 1],
									fc_opblocks[fc_jumpdone]);
					break;
				}

			case EEOP_SBSREF_OLD:
			case EEOP_SBSREF_ASSIGN:
			case EEOP_SBSREF_FETCH:
				{
					LLVMValueRef fc_v_func;
					LLVMValueRef fc_v_params[3];

					fc_v_func = l_ptr_const(fc_op->d.sbsref.subscriptfunc,
										 llvm_pg_var_type("TypeExecEvalSubroutine"));

					fc_v_params[0] = fc_v_state;
					fc_v_params[1] = l_ptr_const(fc_op, l_ptr(StructExprEvalStep));
					fc_v_params[2] = fc_v_econtext;
					l_call(fc_b,
						   LLVMGetFunctionType(ExecEvalSubroutineTemplate),
						   fc_v_func,
						   fc_v_params, lengthof(fc_v_params), "");

					LLVMBuildBr(fc_b, fc_opblocks[fc_opno + 1]);
					break;
				}

			case EEOP_CASE_TESTVAL:
				{
					LLVMBasicBlockRef fc_b_avail,
								fc_b_notavail;
					LLVMValueRef fc_v_casevaluep,
								fc_v_casevalue;
					LLVMValueRef fc_v_casenullp,
								fc_v_casenull;
					LLVMValueRef fc_v_casevaluenull;

					fc_b_avail = l_bb_before_v(fc_opblocks[fc_opno + 1],
											"op.%d.avail", fc_opno);
					fc_b_notavail = l_bb_before_v(fc_opblocks[fc_opno + 1],
											   "op.%d.notavail", fc_opno);

					fc_v_casevaluep = l_ptr_const(fc_op->d.casetest.value,
											   l_ptr(TypeSizeT));
					fc_v_casenullp = l_ptr_const(fc_op->d.casetest.isnull,
											  l_ptr(TypeStorageBool));

					fc_v_casevaluenull =
						LLVMBuildICmp(fc_b, LLVMIntEQ,
									  LLVMBuildPtrToInt(fc_b, fc_v_casevaluep,
														TypeSizeT, ""),
									  l_sizet_const(0), "");
					LLVMBuildCondBr(fc_b, fc_v_casevaluenull, fc_b_notavail, fc_b_avail);

					/* 如果 casetest != NULL */
					LLVMPositionBuilderAtEnd(fc_b, fc_b_avail);
					fc_v_casevalue = l_load(fc_b, TypeSizeT, fc_v_casevaluep, "");
					fc_v_casenull = l_load(fc_b, TypeStorageBool, fc_v_casenullp, "");
					LLVMBuildStore(fc_b, fc_v_casevalue, fc_v_resvaluep);
					LLVMBuildStore(fc_b, fc_v_casenull, fc_v_resnullp);
					LLVMBuildBr(fc_b, fc_opblocks[fc_opno + 1]);

					/* 如果 casetest == NULL */
					LLVMPositionBuilderAtEnd(fc_b, fc_b_notavail);
					fc_v_casevalue =
						l_load_struct_gep(fc_b,
										  StructExprContext,
										  fc_v_econtext,
										  FIELDNO_EXPRCONTEXT_CASEDATUM, "");
					fc_v_casenull =
						l_load_struct_gep(fc_b,
										  StructExprContext,
										  fc_v_econtext,
										  FIELDNO_EXPRCONTEXT_CASENULL, "");
					LLVMBuildStore(fc_b, fc_v_casevalue, fc_v_resvaluep);
					LLVMBuildStore(fc_b, fc_v_casenull, fc_v_resnullp);

					LLVMBuildBr(fc_b, fc_opblocks[fc_opno + 1]);
					break;
				}

			case EEOP_MAKE_READONLY:
				{
					LLVMBasicBlockRef fc_b_notnull;
					LLVMValueRef fc_v_params[1];
					LLVMValueRef fc_v_ret;
					LLVMValueRef fc_v_nullp;
					LLVMValueRef fc_v_valuep;
					LLVMValueRef fc_v_null;
					LLVMValueRef fc_v_value;

					fc_b_notnull = l_bb_before_v(fc_opblocks[fc_opno + 1],
											  "op.%d.readonly.notnull", fc_opno);

					fc_v_nullp = l_ptr_const(fc_op->d.make_readonly.isnull,
										  l_ptr(TypeStorageBool));

					fc_v_null = l_load(fc_b, TypeStorageBool, fc_v_nullp, "");

					/* 将 null isnull 值存储在结果中 */
					LLVMBuildStore(fc_b, fc_v_null, fc_v_resnullp);

					/* 检查值是否为 NULL */
					LLVMBuildCondBr(fc_b,
									LLVMBuildICmp(fc_b, LLVMIntEQ, fc_v_null,
												  l_sbool_const(1), ""),
									fc_opblocks[fc_opno + 1], fc_b_notnull);

					/* 如果值不为 null，将其转换为只读数据 */
					LLVMPositionBuilderAtEnd(fc_b, fc_b_notnull);

					fc_v_valuep = l_ptr_const(fc_op->d.make_readonly.value,
										   l_ptr(TypeSizeT));

					fc_v_value = l_load(fc_b, TypeSizeT, fc_v_valuep, "");

					fc_v_params[0] = fc_v_value;
					fc_v_ret =
						l_call(fc_b,
							   llvm_pg_var_func_type("MakeExpandedObjectReadOnlyInternal"),
							   llvm_pg_func(fc_mod, "MakeExpandedObjectReadOnlyInternal"),
							   fc_v_params, lengthof(fc_v_params), "");
					LLVMBuildStore(fc_b, fc_v_ret, fc_v_resvaluep);

					LLVMBuildBr(fc_b, fc_opblocks[fc_opno + 1]);
					break;
				}

			case EEOP_IOCOERCE:
				{
					FunctionCallInfo fc_fcinfo_out,
								fc_fcinfo_in;
					LLVMValueRef fc_v_fn_out,
								fc_v_fn_in;
					LLVMValueRef fc_v_fcinfo_out,
								fc_v_fcinfo_in;
					LLVMValueRef fc_v_fcinfo_in_isnullp;
					LLVMValueRef fc_v_retval;
					LLVMValueRef fc_v_resvalue;
					LLVMValueRef fc_v_resnull;

					LLVMValueRef fc_v_output_skip;
					LLVMValueRef fc_v_output;

					LLVMBasicBlockRef fc_b_skipoutput;
					LLVMBasicBlockRef fc_b_calloutput;
					LLVMBasicBlockRef fc_b_input;
					LLVMBasicBlockRef fc_b_inputcall;

					fc_fcinfo_out = fc_op->d.iocoerce.fcinfo_data_out;
					fc_fcinfo_in = fc_op->d.iocoerce.fcinfo_data_in;

					fc_b_skipoutput = l_bb_before_v(fc_opblocks[fc_opno + 1],
												 "op.%d.skipoutputnull", fc_opno);
					fc_b_calloutput = l_bb_before_v(fc_opblocks[fc_opno + 1],
												 "op.%d.calloutput", fc_opno);
					fc_b_input = l_bb_before_v(fc_opblocks[fc_opno + 1],
											"op.%d.input", fc_opno);
					fc_b_inputcall = l_bb_before_v(fc_opblocks[fc_opno + 1],
												"op.%d.inputcall", fc_opno);

					fc_v_fn_out = llvm_function_reference(fc_context, fc_b, fc_mod, fc_fcinfo_out);
					fc_v_fn_in = llvm_function_reference(fc_context, fc_b, fc_mod, fc_fcinfo_in);
					fc_v_fcinfo_out = l_ptr_const(fc_fcinfo_out, l_ptr(StructFunctionCallInfoData));
					fc_v_fcinfo_in = l_ptr_const(fc_fcinfo_in, l_ptr(StructFunctionCallInfoData));

					fc_v_fcinfo_in_isnullp =
						l_struct_gep(fc_b,
									 StructFunctionCallInfoData,
									 fc_v_fcinfo_in,
									 FIELDNO_FUNCTIONCALLINFODATA_ISNULL,
									 "v_fcinfo_in_isnull");

					/* 输出函数不在空值上调用 */
					fc_v_resnull = l_load(fc_b, TypeStorageBool, fc_v_resnullp, "");
					LLVMBuildCondBr(fc_b,
									LLVMBuildICmp(fc_b, LLVMIntEQ, fc_v_resnull,
												  l_sbool_const(1), ""),
									fc_b_skipoutput,
									fc_b_calloutput);

					LLVMPositionBuilderAtEnd(fc_b, fc_b_skipoutput);
					fc_v_output_skip = l_sizet_const(0);
					LLVMBuildBr(fc_b, fc_b_input);

					LLVMPositionBuilderAtEnd(fc_b, fc_b_calloutput);
					fc_v_resvalue = l_load(fc_b, TypeSizeT, fc_v_resvaluep, "");

					/* 设置 arg[0] */
					LLVMBuildStore(fc_b,
								   fc_v_resvalue,
								   l_funcvaluep(fc_b, fc_v_fcinfo_out, 0));
					LLVMBuildStore(fc_b,
								   l_sbool_const(0),
								   l_funcnullp(fc_b, fc_v_fcinfo_out, 0));
					/* 并调用输出函数（永远不会返回 NULL） */
					fc_v_output = l_call(fc_b,
									  LLVMGetFunctionType(fc_v_fn_out),
									  fc_v_fn_out, &fc_v_fcinfo_out,
									  1, "funccall_coerce_out");
					LLVMBuildBr(fc_b, fc_b_input);

					/* 构建处理输入函数调用的块 */
					LLVMPositionBuilderAtEnd(fc_b, fc_b_input);

					/* 在 resnull 和输出函数调用分支之间的 phi */
					{
						LLVMValueRef fc_incoming_values[2];
						LLVMBasicBlockRef fc_incoming_blocks[2];

						fc_incoming_values[0] = fc_v_output_skip;
						fc_incoming_blocks[0] = fc_b_skipoutput;

						fc_incoming_values[1] = fc_v_output;
						fc_incoming_blocks[1] = fc_b_calloutput;

						fc_v_output = LLVMBuildPhi(fc_b, TypeSizeT, "output");
						LLVMAddIncoming(fc_v_output,
										fc_incoming_values, fc_incoming_blocks,
										lengthof(fc_incoming_blocks));
					}

					/*
					 * 如果输入函数是严格的，如果输入字符串为
					 * NULL，则跳过。
					 */
					if (fc_op->d.iocoerce.finfo_in->fn_strict)
					{
						LLVMBuildCondBr(fc_b,
										LLVMBuildICmp(fc_b, LLVMIntEQ, fc_v_output,
													  l_sizet_const(0), ""),
										fc_opblocks[fc_opno + 1],
										fc_b_inputcall);
					}
					else
					{
						LLVMBuildBr(fc_b, fc_b_inputcall);
					}

					LLVMPositionBuilderAtEnd(fc_b, fc_b_inputcall);
					/* 设置参数 */
					/* arg0: 输出 */
					LLVMBuildStore(fc_b, fc_v_output,
								   l_funcvaluep(fc_b, fc_v_fcinfo_in, 0));
					LLVMBuildStore(fc_b, fc_v_resnull,
								   l_funcnullp(fc_b, fc_v_fcinfo_in, 0));

					/* arg1: ioparam: 在 execExpr.c 中预设 */
					/* arg2: typmod: preset in execExpr.c  */

					/* 重置 fcinfo_in->isnull */
					LLVMBuildStore(fc_b, l_sbool_const(0), fc_v_fcinfo_in_isnullp);
					/* 并调用函数 */
					fc_v_retval = l_call(fc_b,
									  LLVMGetFunctionType(fc_v_fn_in),
									  fc_v_fn_in, &fc_v_fcinfo_in, 1,
									  "funccall_iocoerce_in");

					LLVMBuildStore(fc_b, fc_v_retval, fc_v_resvaluep);

					LLVMBuildBr(fc_b, fc_opblocks[fc_opno + 1]);
					break;
				}

			case EEOP_DISTINCT:
			case EEOP_NOT_DISTINCT:
				{
					FunctionCallInfo fcinfo = fc_op->d.func.fcinfo_data;

					LLVMValueRef fc_v_fcinfo;
					LLVMValueRef fc_v_fcinfo_isnull;

					LLVMValueRef fc_v_argnull0,
								fc_v_argisnull0;
					LLVMValueRef fc_v_argnull1,
								fc_v_argisnull1;

					LLVMValueRef fc_v_anyargisnull;
					LLVMValueRef fc_v_bothargisnull;

					LLVMValueRef fc_v_result;

					LLVMBasicBlockRef fc_b_noargnull;
					LLVMBasicBlockRef fc_b_checkbothargnull;
					LLVMBasicBlockRef fc_b_bothargnull;
					LLVMBasicBlockRef fc_b_anyargnull;

					fc_b_noargnull = l_bb_before_v(fc_opblocks[fc_opno + 1], "op.%d.noargnull", fc_opno);
					fc_b_checkbothargnull = l_bb_before_v(fc_opblocks[fc_opno + 1], "op.%d.checkbothargnull", fc_opno);
					fc_b_bothargnull = l_bb_before_v(fc_opblocks[fc_opno + 1], "op.%d.bothargnull", fc_opno);
					fc_b_anyargnull = l_bb_before_v(fc_opblocks[fc_opno + 1], "op.%d.anyargnull", fc_opno);

					fc_v_fcinfo = l_ptr_const(fcinfo, l_ptr(StructFunctionCallInfoData));

					/* 加载 args[0|1].isnull 作为两个参数 */
					fc_v_argnull0 = l_funcnull(fc_b, fc_v_fcinfo, 0);
					fc_v_argisnull0 = LLVMBuildICmp(fc_b, LLVMIntEQ, fc_v_argnull0,
												 l_sbool_const(1), "");
					fc_v_argnull1 = l_funcnull(fc_b, fc_v_fcinfo, 1);
					fc_v_argisnull1 = LLVMBuildICmp(fc_b, LLVMIntEQ, fc_v_argnull1,
												 l_sbool_const(1), "");

					fc_v_anyargisnull = LLVMBuildOr(fc_b, fc_v_argisnull0, fc_v_argisnull1, "");
					fc_v_bothargisnull = LLVMBuildAnd(fc_b, fc_v_argisnull0, fc_v_argisnull1, "");

					/*
					 * 检查函数参数是否为 NULL：如果任一为 NULL，
					 * 我们检查两个参数是否都为 NULL。否则调用
					 * 比较器。
					 */
					LLVMBuildCondBr(fc_b, fc_v_anyargisnull, fc_b_checkbothargnull,
									fc_b_noargnull);

					/*
					 * 构建块检查是否有任何参数为 null
					 */
					LLVMPositionBuilderAtEnd(fc_b, fc_b_checkbothargnull);
					LLVMBuildCondBr(fc_b, fc_v_bothargisnull, fc_b_bothargnull,
									fc_b_anyargnull);


					/* 两者都是 NULL？那么不是不同... */
					LLVMPositionBuilderAtEnd(fc_b, fc_b_bothargnull);
					LLVMBuildStore(fc_b, l_sbool_const(0), fc_v_resnullp);
					if (fc_opcode == EEOP_NOT_DISTINCT)
						LLVMBuildStore(fc_b, l_sizet_const(1), fc_v_resvaluep);
					else
						LLVMBuildStore(fc_b, l_sizet_const(0), fc_v_resvaluep);

					LLVMBuildBr(fc_b, fc_opblocks[fc_opno + 1]);

					/* 只有一个是 NULL？那么是不同... */
					LLVMPositionBuilderAtEnd(fc_b, fc_b_anyargnull);
					LLVMBuildStore(fc_b, l_sbool_const(0), fc_v_resnullp);
					if (fc_opcode == EEOP_NOT_DISTINCT)
						LLVMBuildStore(fc_b, l_sizet_const(0), fc_v_resvaluep);
					else
						LLVMBuildStore(fc_b, l_sizet_const(1), fc_v_resvaluep);
					LLVMBuildBr(fc_b, fc_opblocks[fc_opno + 1]);

					/* 两个参数都不是 null：比较 */
					LLVMPositionBuilderAtEnd(fc_b, fc_b_noargnull);

					fc_v_result = fc_BuildV1Call(fc_context, fc_b, fc_mod, fcinfo,
										   &fc_v_fcinfo_isnull);

					if (fc_opcode == EEOP_DISTINCT)
					{
						/* 必须反转 "=" 的结果 */
						fc_v_result =
							LLVMBuildZExt(fc_b,
										  LLVMBuildICmp(fc_b, LLVMIntEQ,
														fc_v_result,
														l_sizet_const(0), ""),
										  TypeSizeT, "");
					}

					LLVMBuildStore(fc_b, fc_v_fcinfo_isnull, fc_v_resnullp);
					LLVMBuildStore(fc_b, fc_v_result, fc_v_resvaluep);

					LLVMBuildBr(fc_b, fc_opblocks[fc_opno + 1]);
					break;
				}

			case EEOP_NULLIF:
				{
					FunctionCallInfo fcinfo = fc_op->d.func.fcinfo_data;

					LLVMValueRef fc_v_fcinfo;
					LLVMValueRef fc_v_fcinfo_isnull;
					LLVMValueRef fc_v_argnull0;
					LLVMValueRef fc_v_argnull1;
					LLVMValueRef fc_v_anyargisnull;
					LLVMValueRef fc_v_arg0;
					LLVMBasicBlockRef fc_b_hasnull;
					LLVMBasicBlockRef fc_b_nonull;
					LLVMBasicBlockRef fc_b_argsequal;
					LLVMValueRef fc_v_retval;
					LLVMValueRef fc_v_argsequal;

					fc_b_hasnull = l_bb_before_v(fc_opblocks[fc_opno + 1],
											  "b.%d.null-args", fc_opno);
					fc_b_nonull = l_bb_before_v(fc_opblocks[fc_opno + 1],
											 "b.%d.no-null-args", fc_opno);
					fc_b_argsequal = l_bb_before_v(fc_opblocks[fc_opno + 1],
												"b.%d.argsequal", fc_opno);

					fc_v_fcinfo = l_ptr_const(fcinfo, l_ptr(StructFunctionCallInfoData));

					/* 保存原始 arg[0] */
					fc_v_arg0 = l_funcvalue(fc_b, fc_v_fcinfo, 0);

					/* 如果任一参数为 NULL，则它们不能相等 */
					fc_v_argnull0 = l_funcnull(fc_b, fc_v_fcinfo, 0);
					fc_v_argnull1 = l_funcnull(fc_b, fc_v_fcinfo, 1);

					fc_v_anyargisnull =
						LLVMBuildOr(fc_b,
									LLVMBuildICmp(fc_b, LLVMIntEQ, fc_v_argnull0,
												  l_sbool_const(1), ""),
									LLVMBuildICmp(fc_b, LLVMIntEQ, fc_v_argnull1,
												  l_sbool_const(1), ""),
									"");

					LLVMBuildCondBr(fc_b, fc_v_anyargisnull, fc_b_hasnull, fc_b_nonull);

					/* 一个（或两个）参数为 null，返回 arg[0] */
					LLVMPositionBuilderAtEnd(fc_b, fc_b_hasnull);
					LLVMBuildStore(fc_b, fc_v_argnull0, fc_v_resnullp);
					LLVMBuildStore(fc_b, fc_v_arg0, fc_v_resvaluep);
					LLVMBuildBr(fc_b, fc_opblocks[fc_opno + 1]);

					/* 构建块以调用函数并检查结果 */
					LLVMPositionBuilderAtEnd(fc_b, fc_b_nonull);

					/*
					 * 如果第一个参数是 varlena 类型，它可能是一个
					 * 扩展的数据项。我们需要确保传递给比较函数的
					 * 值是只读指针。然而，如果我们最终返回第一个
					 * 参数，如果它是可读写的，那将是原始的可读写指针。
					 */
					if (fc_op->d.func.make_ro)
					{
						LLVMValueRef fc_v_params[1];
						LLVMValueRef fc_v_arg0_ro;

						fc_v_params[0] = fc_v_arg0;
						fc_v_arg0_ro =
							l_call(fc_b,
								   llvm_pg_var_func_type("MakeExpandedObjectReadOnlyInternal"),
								   llvm_pg_func(fc_mod, "MakeExpandedObjectReadOnlyInternal"),
								   fc_v_params, lengthof(fc_v_params), "");
						LLVMBuildStore(fc_b, fc_v_arg0_ro,
									   l_funcvaluep(fc_b, fc_v_fcinfo, 0));
					}

					fc_v_retval = fc_BuildV1Call(fc_context, fc_b, fc_mod, fcinfo, &fc_v_fcinfo_isnull);

					/*
					 * 如果结果不是 null 并且参数相等，则返回 null，
					 * 否则返回 arg[0]（与有 NULL 时的结果相同，
					 * 因此重用 b_hasnull）。
					 */
					fc_v_argsequal = LLVMBuildAnd(fc_b,
											   LLVMBuildICmp(fc_b, LLVMIntEQ,
															 fc_v_fcinfo_isnull,
															 l_sbool_const(0),
															 ""),
											   LLVMBuildICmp(fc_b, LLVMIntEQ,
															 fc_v_retval,
															 l_sizet_const(1),
															 ""),
											   "");
					LLVMBuildCondBr(fc_b, fc_v_argsequal, fc_b_argsequal, fc_b_hasnull);

					/* 构建块设置结果为 NULL，如果参数相等 */
					LLVMPositionBuilderAtEnd(fc_b, fc_b_argsequal);
					LLVMBuildStore(fc_b, l_sbool_const(1), fc_v_resnullp);
					LLVMBuildStore(fc_b, l_sizet_const(0), fc_v_resvaluep);
					LLVMBuildStore(fc_b, fc_v_retval, fc_v_resvaluep);

					LLVMBuildBr(fc_b, fc_opblocks[fc_opno + 1]);
					break;
				}

			case EEOP_SQLVALUEFUNCTION:
				build_EvalXFunc(fc_b, fc_mod, "ExecEvalSQLValueFunction",
								fc_v_state, fc_op);
				LLVMBuildBr(fc_b, fc_opblocks[fc_opno + 1]);
				break;

			case EEOP_CURRENTOFEXPR:
				build_EvalXFunc(fc_b, fc_mod, "ExecEvalCurrentOfExpr",
								fc_v_state, fc_op);
				LLVMBuildBr(fc_b, fc_opblocks[fc_opno + 1]);
				break;

			case EEOP_NEXTVALUEEXPR:
				build_EvalXFunc(fc_b, fc_mod, "ExecEvalNextValueExpr",
								fc_v_state, fc_op);
				LLVMBuildBr(fc_b, fc_opblocks[fc_opno + 1]);
				break;

			case EEOP_ARRAYEXPR:
				build_EvalXFunc(fc_b, fc_mod, "ExecEvalArrayExpr",
								fc_v_state, fc_op);
				LLVMBuildBr(fc_b, fc_opblocks[fc_opno + 1]);
				break;

			case EEOP_ARRAYCOERCE:
				build_EvalXFunc(fc_b, fc_mod, "ExecEvalArrayCoerce",
								fc_v_state, fc_op, fc_v_econtext);
				LLVMBuildBr(fc_b, fc_opblocks[fc_opno + 1]);
				break;

			case EEOP_ROW:
				build_EvalXFunc(fc_b, fc_mod, "ExecEvalRow",
								fc_v_state, fc_op);
				LLVMBuildBr(fc_b, fc_opblocks[fc_opno + 1]);
				break;

			case EEOP_ROWCOMPARE_STEP:
				{
					FunctionCallInfo fcinfo = fc_op->d.rowcompare_step.fcinfo_data;
					LLVMValueRef fc_v_fcinfo_isnull;
					LLVMBasicBlockRef fc_b_null;
					LLVMBasicBlockRef fc_b_compare;
					LLVMBasicBlockRef fc_b_compare_result;

					LLVMValueRef fc_v_retval;

					fc_b_null = l_bb_before_v(fc_opblocks[fc_opno + 1],
										   "op.%d.row-null", fc_opno);
					fc_b_compare = l_bb_before_v(fc_opblocks[fc_opno + 1],
											  "op.%d.row-compare", fc_opno);
					fc_b_compare_result =
						l_bb_before_v(fc_opblocks[fc_opno + 1],
									  "op.%d.row-compare-result",
									  fc_opno);

					/*
					 * 如果函数是严格的，并且任一参数为 null，我们
					 * 就完成了。
					 */
					if (fc_op->d.rowcompare_step.finfo->fn_strict)
					{
						LLVMValueRef fc_v_fcinfo;
						LLVMValueRef fc_v_argnull0;
						LLVMValueRef fc_v_argnull1;
						LLVMValueRef fc_v_anyargisnull;

						fc_v_fcinfo = l_ptr_const(fcinfo,
											   l_ptr(StructFunctionCallInfoData));

						fc_v_argnull0 = l_funcnull(fc_b, fc_v_fcinfo, 0);
						fc_v_argnull1 = l_funcnull(fc_b, fc_v_fcinfo, 1);

						fc_v_anyargisnull =
							LLVMBuildOr(fc_b,
										LLVMBuildICmp(fc_b,
													  LLVMIntEQ,
													  fc_v_argnull0,
													  l_sbool_const(1),
													  ""),
										LLVMBuildICmp(fc_b, LLVMIntEQ,
													  fc_v_argnull1,
													  l_sbool_const(1), ""),
										"");

						LLVMBuildCondBr(fc_b, fc_v_anyargisnull, fc_b_null, fc_b_compare);
					}
					else
					{
						LLVMBuildBr(fc_b, fc_b_compare);
					}

					/* 构建块调用比较函数 */
					LLVMPositionBuilderAtEnd(fc_b, fc_b_compare);

					/* 调用函数 */
					fc_v_retval = fc_BuildV1Call(fc_context, fc_b, fc_mod, fcinfo,
										   &fc_v_fcinfo_isnull);
					LLVMBuildStore(fc_b, fc_v_retval, fc_v_resvaluep);

					/* 如果函数结果为 NULL，强制结果为 NULL */
					LLVMBuildCondBr(fc_b,
									LLVMBuildICmp(fc_b,
												  LLVMIntEQ,
												  fc_v_fcinfo_isnull,
												  l_sbool_const(0),
												  ""),
									fc_b_compare_result,
									fc_b_null);

					/* 构建块分析 !NULL 比较器结果 */
					LLVMPositionBuilderAtEnd(fc_b, fc_b_compare_result);

					/* 如果结果相等，则比较下一个，否则完成 */
					LLVMBuildCondBr(fc_b,
									LLVMBuildICmp(fc_b,
												  LLVMIntEQ,
												  fc_v_retval,
												  l_sizet_const(0), ""),
									fc_opblocks[fc_opno + 1],
									fc_opblocks[fc_op->d.rowcompare_step.jumpdone]);

					/*
					 * 构建块处理 NULL 输入或 NULL 比较器
					 * 结果。
					 */
					LLVMPositionBuilderAtEnd(fc_b, fc_b_null);
					LLVMBuildStore(fc_b, l_sbool_const(1), fc_v_resnullp);
					LLVMBuildBr(fc_b, fc_opblocks[fc_op->d.rowcompare_step.jumpnull]);

					break;
				}

			case EEOP_ROWCOMPARE_FINAL:
				{
					RowCompareType fc_rctype = fc_op->d.rowcompare_final.rctype;

					LLVMValueRef fc_v_cmpresult;
					LLVMValueRef fc_v_result;
					LLVMIntPredicate fc_predicate;

					/*
					 * Btree 比较器返回 32 位结果，需小心符号
					 * （作为 64 位值使用时，它会是错误的）。
					 */
					fc_v_cmpresult =
						LLVMBuildTrunc(fc_b,
									   l_load(fc_b, TypeSizeT, fc_v_resvaluep, ""),
									   LLVMInt32TypeInContext(fc_lc), "");

					switch (fc_rctype)
					{
						case ROWCOMPARE_LT:
							fc_predicate = LLVMIntSLT;
							break;
						case ROWCOMPARE_LE:
							fc_predicate = LLVMIntSLE;
							break;
						case ROWCOMPARE_GT:
							fc_predicate = LLVMIntSGT;
							break;
						case ROWCOMPARE_GE:
							fc_predicate = LLVMIntSGE;
							break;
						default:
							/* EQ和NE情况在这里不被允许 */
							Assert(false);
							fc_predicate = 0;	/* 防止编译器警告 */
							break;
					}

					fc_v_result = LLVMBuildICmp(fc_b,
											 fc_predicate,
											 fc_v_cmpresult,
											 l_int32_const(fc_lc, 0),
											 "");
					fc_v_result = LLVMBuildZExt(fc_b, fc_v_result, TypeSizeT, "");

					LLVMBuildStore(fc_b, l_sbool_const(0), fc_v_resnullp);
					LLVMBuildStore(fc_b, fc_v_result, fc_v_resvaluep);

					LLVMBuildBr(fc_b, fc_opblocks[fc_opno + 1]);
					break;
				}

			case EEOP_MINMAX:
				build_EvalXFunc(fc_b, fc_mod, "ExecEvalMinMax",
								fc_v_state, fc_op);
				LLVMBuildBr(fc_b, fc_opblocks[fc_opno + 1]);
				break;

			case EEOP_FIELDSELECT:
				build_EvalXFunc(fc_b, fc_mod, "ExecEvalFieldSelect",
								fc_v_state, fc_op, fc_v_econtext);
				LLVMBuildBr(fc_b, fc_opblocks[fc_opno + 1]);
				break;

			case EEOP_FIELDSTORE_DEFORM:
				build_EvalXFunc(fc_b, fc_mod, "ExecEvalFieldStoreDeForm",
								fc_v_state, fc_op, fc_v_econtext);
				LLVMBuildBr(fc_b, fc_opblocks[fc_opno + 1]);
				break;

			case EEOP_FIELDSTORE_FORM:
				build_EvalXFunc(fc_b, fc_mod, "ExecEvalFieldStoreForm",
								fc_v_state, fc_op, fc_v_econtext);
				LLVMBuildBr(fc_b, fc_opblocks[fc_opno + 1]);
				break;

			case EEOP_DOMAIN_TESTVAL:
				{
					LLVMBasicBlockRef fc_b_avail,
								fc_b_notavail;
					LLVMValueRef fc_v_casevaluep,
								fc_v_casevalue;
					LLVMValueRef fc_v_casenullp,
								fc_v_casenull;
					LLVMValueRef fc_v_casevaluenull;

					fc_b_avail = l_bb_before_v(fc_opblocks[fc_opno + 1],
											"op.%d.avail", fc_opno);
					fc_b_notavail = l_bb_before_v(fc_opblocks[fc_opno + 1],
											   "op.%d.notavail", fc_opno);

					fc_v_casevaluep = l_ptr_const(fc_op->d.casetest.value,
											   l_ptr(TypeSizeT));
					fc_v_casenullp = l_ptr_const(fc_op->d.casetest.isnull,
											  l_ptr(TypeStorageBool));

					fc_v_casevaluenull =
						LLVMBuildICmp(fc_b, LLVMIntEQ,
									  LLVMBuildPtrToInt(fc_b, fc_v_casevaluep,
														TypeSizeT, ""),
									  l_sizet_const(0), "");
					LLVMBuildCondBr(fc_b,
									fc_v_casevaluenull,
									fc_b_notavail, fc_b_avail);

					/* 如果 casetest != NULL */
					LLVMPositionBuilderAtEnd(fc_b, fc_b_avail);
					fc_v_casevalue = l_load(fc_b, TypeSizeT, fc_v_casevaluep, "");
					fc_v_casenull = l_load(fc_b, TypeStorageBool, fc_v_casenullp, "");
					LLVMBuildStore(fc_b, fc_v_casevalue, fc_v_resvaluep);
					LLVMBuildStore(fc_b, fc_v_casenull, fc_v_resnullp);
					LLVMBuildBr(fc_b, fc_opblocks[fc_opno + 1]);

					/* 如果 casetest == NULL */
					LLVMPositionBuilderAtEnd(fc_b, fc_b_notavail);
					fc_v_casevalue =
						l_load_struct_gep(fc_b,
										  StructExprContext,
										  fc_v_econtext,
										  FIELDNO_EXPRCONTEXT_DOMAINDATUM,
										  "");
					fc_v_casenull =
						l_load_struct_gep(fc_b,
										  StructExprContext,
										  fc_v_econtext,
										  FIELDNO_EXPRCONTEXT_DOMAINNULL,
										  "");
					LLVMBuildStore(fc_b, fc_v_casevalue, fc_v_resvaluep);
					LLVMBuildStore(fc_b, fc_v_casenull, fc_v_resnullp);

					LLVMBuildBr(fc_b, fc_opblocks[fc_opno + 1]);
					break;
				}

			case EEOP_DOMAIN_NOTNULL:
				build_EvalXFunc(fc_b, fc_mod, "ExecEvalConstraintNotNull",
								fc_v_state, fc_op);
				LLVMBuildBr(fc_b, fc_opblocks[fc_opno + 1]);
				break;

			case EEOP_DOMAIN_CHECK:
				build_EvalXFunc(fc_b, fc_mod, "ExecEvalConstraintCheck",
								fc_v_state, fc_op);
				LLVMBuildBr(fc_b, fc_opblocks[fc_opno + 1]);
				break;

			case EEOP_CONVERT_ROWTYPE:
				build_EvalXFunc(fc_b, fc_mod, "ExecEvalConvertRowtype",
								fc_v_state, fc_op, fc_v_econtext);
				LLVMBuildBr(fc_b, fc_opblocks[fc_opno + 1]);
				break;

			case EEOP_SCALARARRAYOP:
				build_EvalXFunc(fc_b, fc_mod, "ExecEvalScalarArrayOp",
								fc_v_state, fc_op);
				LLVMBuildBr(fc_b, fc_opblocks[fc_opno + 1]);
				break;

			case EEOP_HASHED_SCALARARRAYOP:
				build_EvalXFunc(fc_b, fc_mod, "ExecEvalHashedScalarArrayOp",
								fc_v_state, fc_op, fc_v_econtext);
				LLVMBuildBr(fc_b, fc_opblocks[fc_opno + 1]);
				break;

			case EEOP_XMLEXPR:
				build_EvalXFunc(fc_b, fc_mod, "ExecEvalXmlExpr",
								fc_v_state, fc_op);
				LLVMBuildBr(fc_b, fc_opblocks[fc_opno + 1]);
				break;

			case EEOP_AGGREF:
				{
					LLVMValueRef fc_v_aggno;
					LLVMValueRef fc_value,
								fc_isnull;

					fc_v_aggno = l_int32_const(fc_lc, fc_op->d.aggref.aggno);

					/* 加载聚合值 / null */
					fc_value = l_load_gep1(fc_b, TypeSizeT, fc_v_aggvalues, fc_v_aggno, "aggvalue");
					fc_isnull = l_load_gep1(fc_b, TypeStorageBool, fc_v_aggnulls, fc_v_aggno, "aggnull");

					/* 并存储结果 */
					LLVMBuildStore(fc_b, fc_value, fc_v_resvaluep);
					LLVMBuildStore(fc_b, fc_isnull, fc_v_resnullp);

					LLVMBuildBr(fc_b, fc_opblocks[fc_opno + 1]);
					break;
				}

			case EEOP_GROUPING_FUNC:
				build_EvalXFunc(fc_b, fc_mod, "ExecEvalGroupingFunc",
								fc_v_state, fc_op);
				LLVMBuildBr(fc_b, fc_opblocks[fc_opno + 1]);
				break;

			case EEOP_WINDOW_FUNC:
				{
					WindowFuncExprState *fc_wfunc = fc_op->d.window_func.wfstate;
					LLVMValueRef fc_v_wfuncnop;
					LLVMValueRef fc_v_wfuncno;
					LLVMValueRef fc_value,
								fc_isnull;

					/*
					 * 此时 aggref->wfuncno 尚未设置（在初始化
					 * 表达式后，它在 ExecInitWindowAgg() 中设置）。
					 * 所以每次循环时从内存中加载它。
					 */
					fc_v_wfuncnop = l_ptr_const(&fc_wfunc->wfuncno,
											 l_ptr(LLVMInt32TypeInContext(fc_lc)));
					fc_v_wfuncno = l_load(fc_b, LLVMInt32TypeInContext(fc_lc), fc_v_wfuncnop, "v_wfuncno");

					/* 加载窗口函数值 / null */
					fc_value = l_load_gep1(fc_b, TypeSizeT, fc_v_aggvalues, fc_v_wfuncno,
										"windowvalue");
					fc_isnull = l_load_gep1(fc_b, TypeStorageBool, fc_v_aggnulls, fc_v_wfuncno,
										 "windownull");

					LLVMBuildStore(fc_b, fc_value, fc_v_resvaluep);
					LLVMBuildStore(fc_b, fc_isnull, fc_v_resnullp);

					LLVMBuildBr(fc_b, fc_opblocks[fc_opno + 1]);
					break;
				}

			case EEOP_SUBPLAN:
				build_EvalXFunc(fc_b, fc_mod, "ExecEvalSubPlan",
								fc_v_state, fc_op, fc_v_econtext);
				LLVMBuildBr(fc_b, fc_opblocks[fc_opno + 1]);
				break;

			case EEOP_AGG_STRICT_DESERIALIZE:
			case EEOP_AGG_DESERIALIZE:
				{
					AggState   *fc_aggstate;
					FunctionCallInfo fcinfo = fc_op->d.agg_deserialize.fcinfo_data;

					LLVMValueRef fc_v_retval;
					LLVMValueRef fc_v_fcinfo_isnull;
					LLVMValueRef fc_v_tmpcontext;
					LLVMValueRef fc_v_oldcontext;

					if (fc_opcode == EEOP_AGG_STRICT_DESERIALIZE)
					{
						LLVMValueRef fc_v_fcinfo;
						LLVMValueRef fc_v_argnull0;
						LLVMBasicBlockRef fc_b_deserialize;

						fc_b_deserialize = l_bb_before_v(fc_opblocks[fc_opno + 1],
													  "op.%d.deserialize", fc_opno);

						fc_v_fcinfo = l_ptr_const(fcinfo,
											   l_ptr(StructFunctionCallInfoData));
						fc_v_argnull0 = l_funcnull(fc_b, fc_v_fcinfo, 0);

						LLVMBuildCondBr(fc_b,
										LLVMBuildICmp(fc_b,
													  LLVMIntEQ,
													  fc_v_argnull0,
													  l_sbool_const(1),
													  ""),
										fc_opblocks[fc_op->d.agg_deserialize.jumpnull],
										fc_b_deserialize);
						LLVMPositionBuilderAtEnd(fc_b, fc_b_deserialize);
					}

					fc_aggstate = castNode(AggState, fc_state->parent);
					fcinfo = fc_op->d.agg_deserialize.fcinfo_data;

					fc_v_tmpcontext =
						l_ptr_const(fc_aggstate->tmpcontext->ecxt_per_tuple_memory,
									l_ptr(StructMemoryContextData));
					fc_v_oldcontext = l_mcxt_switch(fc_mod, fc_b, fc_v_tmpcontext);
					fc_v_retval = fc_BuildV1Call(fc_context, fc_b, fc_mod, fcinfo,
										   &fc_v_fcinfo_isnull);
					l_mcxt_switch(fc_mod, fc_b, fc_v_oldcontext);

					LLVMBuildStore(fc_b, fc_v_retval, fc_v_resvaluep);
					LLVMBuildStore(fc_b, fc_v_fcinfo_isnull, fc_v_resnullp);

					LLVMBuildBr(fc_b, fc_opblocks[fc_opno + 1]);
					break;
				}

			case EEOP_AGG_STRICT_INPUT_CHECK_ARGS:
			case EEOP_AGG_STRICT_INPUT_CHECK_NULLS:
				{
					int			fc_nargs = fc_op->d.agg_strict_input_check.nargs;
					NullableDatum *fc_args = fc_op->d.agg_strict_input_check.args;
					bool	   *fc_nulls = fc_op->d.agg_strict_input_check.nulls;
					int			fc_jumpnull;

					LLVMValueRef fc_v_argsp;
					LLVMValueRef fc_v_nullsp;
					LLVMBasicBlockRef *fc_b_checknulls;

					Assert(fc_nargs > 0);

					fc_jumpnull = fc_op->d.agg_strict_input_check.jumpnull;
					fc_v_argsp = l_ptr_const(fc_args, l_ptr(StructNullableDatum));
					fc_v_nullsp = l_ptr_const(fc_nulls, l_ptr(TypeStorageBool));

					/* 创建检查参数的块 */
					fc_b_checknulls = palloc(sizeof(LLVMBasicBlockRef *) * fc_nargs);
					for (int fc_argno = 0; fc_argno < fc_nargs; fc_argno++)
					{
						fc_b_checknulls[fc_argno] =
							l_bb_before_v(fc_opblocks[fc_opno + 1],
										  "op.%d.check-null.%d",
										  fc_opno, fc_argno);
					}

					LLVMBuildBr(fc_b, fc_b_checknulls[0]);

					/* 严格函数，检查 NULL 参数 */
					for (int fc_argno = 0; fc_argno < fc_nargs; fc_argno++)
					{
						LLVMValueRef fc_v_argno = l_int32_const(fc_lc, fc_argno);
						LLVMValueRef fc_v_argisnull;
						LLVMBasicBlockRef fc_b_argnotnull;

						LLVMPositionBuilderAtEnd(fc_b, fc_b_checknulls[fc_argno]);

						if (fc_argno + 1 == fc_nargs)
							fc_b_argnotnull = fc_opblocks[fc_opno + 1];
						else
							fc_b_argnotnull = fc_b_checknulls[fc_argno + 1];

						if (fc_opcode == EEOP_AGG_STRICT_INPUT_CHECK_NULLS)
							fc_v_argisnull = l_load_gep1(fc_b, TypeStorageBool, fc_v_nullsp, fc_v_argno, "");
						else
						{
							LLVMValueRef fc_v_argn;

							fc_v_argn = l_gep(fc_b, StructNullableDatum, fc_v_argsp, &fc_v_argno, 1, "");
							fc_v_argisnull =
								l_load_struct_gep(fc_b, StructNullableDatum, fc_v_argn,
												  FIELDNO_NULLABLE_DATUM_ISNULL,
												  "");
						}

						LLVMBuildCondBr(fc_b,
										LLVMBuildICmp(fc_b,
													  LLVMIntEQ,
													  fc_v_argisnull,
													  l_sbool_const(1), ""),
										fc_opblocks[fc_jumpnull],
										fc_b_argnotnull);
					}

					break;
				}

			case EEOP_AGG_PLAIN_PERGROUP_NULLCHECK:
				{
					int			fc_jumpnull;
					LLVMValueRef fc_v_aggstatep;
					LLVMValueRef fc_v_allpergroupsp;
					LLVMValueRef fc_v_pergroup_allaggs;
					LLVMValueRef fc_v_setoff;

					fc_jumpnull = fc_op->d.agg_plain_pergroup_nullcheck.jumpnull;

					/*
					 * pergroup_allaggs = aggstate->all_pergroups
					 * [op->d.agg_plain_pergroup_nullcheck.setoff];
					 */
					fc_v_aggstatep = LLVMBuildBitCast(fc_b, fc_v_parent,
												   l_ptr(StructAggState), "");

					fc_v_allpergroupsp = l_load_struct_gep(fc_b,
														StructAggState,
														fc_v_aggstatep,
														FIELDNO_AGGSTATE_ALL_PERGROUPS,
														"aggstate.all_pergroups");

					fc_v_setoff = l_int32_const(fc_lc, fc_op->d.agg_plain_pergroup_nullcheck.setoff);

					fc_v_pergroup_allaggs = l_load_gep1(fc_b, l_ptr(StructAggStatePerGroupData),
													 fc_v_allpergroupsp, fc_v_setoff, "");

					LLVMBuildCondBr(fc_b,
									LLVMBuildICmp(fc_b, LLVMIntEQ,
												  LLVMBuildPtrToInt(fc_b, fc_v_pergroup_allaggs, TypeSizeT, ""),
												  l_sizet_const(0), ""),
									fc_opblocks[fc_jumpnull],
									fc_opblocks[fc_opno + 1]);
					break;
				}

			case EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL:
			case EEOP_AGG_PLAIN_TRANS_STRICT_BYVAL:
			case EEOP_AGG_PLAIN_TRANS_BYVAL:
			case EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYREF:
			case EEOP_AGG_PLAIN_TRANS_STRICT_BYREF:
			case EEOP_AGG_PLAIN_TRANS_BYREF:
				{
					AggState   *fc_aggstate;
					AggStatePerTrans fc_pertrans;
					FunctionCallInfo fcinfo;

					LLVMValueRef fc_v_aggstatep;
					LLVMValueRef fc_v_fcinfo;
					LLVMValueRef fc_v_fcinfo_isnull;

					LLVMValueRef fc_v_transvaluep;
					LLVMValueRef fc_v_transnullp;

					LLVMValueRef fc_v_setoff;
					LLVMValueRef fc_v_transno;

					LLVMValueRef fc_v_aggcontext;

					LLVMValueRef fc_v_allpergroupsp;
					LLVMValueRef fc_v_current_setp;
					LLVMValueRef fc_v_current_pertransp;
					LLVMValueRef fc_v_curaggcontext;

					LLVMValueRef fc_v_pertransp;

					LLVMValueRef fc_v_pergroupp;

					LLVMValueRef fc_v_retval;

					LLVMValueRef fc_v_tmpcontext;
					LLVMValueRef fc_v_oldcontext;

					fc_aggstate = castNode(AggState, fc_state->parent);
					fc_pertrans = fc_op->d.agg_trans.pertrans;

					fcinfo = fc_pertrans->transfn_fcinfo;

					fc_v_aggstatep =
						LLVMBuildBitCast(fc_b, fc_v_parent, l_ptr(StructAggState), "");
					fc_v_pertransp = l_ptr_const(fc_pertrans,
											  l_ptr(StructAggStatePerTransData));

					/*
					 * pergroup = &aggstate->all_pergroups
					 * [op->d.agg_strict_trans_check.setoff]
					 * [op->d.agg_init_trans_check.transno];
					 */
					fc_v_allpergroupsp =
						l_load_struct_gep(fc_b,
										  StructAggState,
										  fc_v_aggstatep,
										  FIELDNO_AGGSTATE_ALL_PERGROUPS,
										  "aggstate.all_pergroups");
					fc_v_setoff = l_int32_const(fc_lc, fc_op->d.agg_trans.setoff);
					fc_v_transno = l_int32_const(fc_lc, fc_op->d.agg_trans.transno);
					fc_v_pergroupp =
						l_gep(fc_b,
							  StructAggStatePerGroupData,
							  l_load_gep1(fc_b, l_ptr(StructAggStatePerGroupData),
										  fc_v_allpergroupsp, fc_v_setoff, ""),
							  &fc_v_transno, 1, "");


					if (fc_opcode == EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL ||
						fc_opcode == EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYREF)
					{
						LLVMValueRef fc_v_notransvalue;
						LLVMBasicBlockRef fc_b_init;
						LLVMBasicBlockRef fc_b_no_init;

						fc_v_notransvalue =
							l_load_struct_gep(fc_b,
											  StructAggStatePerGroupData,
											  fc_v_pergroupp,
											  FIELDNO_AGGSTATEPERGROUPDATA_NOTRANSVALUE,
											  "notransvalue");

						fc_b_init = l_bb_before_v(fc_opblocks[fc_opno + 1],
											   "op.%d.inittrans", fc_opno);
						fc_b_no_init = l_bb_before_v(fc_opblocks[fc_opno + 1],
												  "op.%d.no_inittrans", fc_opno);

						LLVMBuildCondBr(fc_b,
										LLVMBuildICmp(fc_b, LLVMIntEQ, fc_v_notransvalue,
													  l_sbool_const(1), ""),
										fc_b_init,
										fc_b_no_init);

						/* 如果需要，初始化转换值的块 */
						{
							LLVMValueRef fc_params[4];

							LLVMPositionBuilderAtEnd(fc_b, fc_b_init);

							fc_v_aggcontext = l_ptr_const(fc_op->d.agg_trans.aggcontext,
													   l_ptr(StructExprContext));

							fc_params[0] = fc_v_aggstatep;
							fc_params[1] = fc_v_pertransp;
							fc_params[2] = fc_v_pergroupp;
							fc_params[3] = fc_v_aggcontext;

							l_call(fc_b,
								   llvm_pg_var_func_type("ExecAggInitGroup"),
								   llvm_pg_func(fc_mod, "ExecAggInitGroup"),
								   fc_params, lengthof(fc_params),
								   "");

							LLVMBuildBr(fc_b, fc_opblocks[fc_opno + 1]);
						}

						LLVMPositionBuilderAtEnd(fc_b, fc_b_no_init);
					}

					if (fc_opcode == EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL ||
						fc_opcode == EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYREF ||
						fc_opcode == EEOP_AGG_PLAIN_TRANS_STRICT_BYVAL ||
						fc_opcode == EEOP_AGG_PLAIN_TRANS_STRICT_BYREF)
					{
						LLVMValueRef fc_v_transnull;
						LLVMBasicBlockRef fc_b_strictpass;

						fc_b_strictpass = l_bb_before_v(fc_opblocks[fc_opno + 1],
													 "op.%d.strictpass", fc_opno);
						fc_v_transnull =
							l_load_struct_gep(fc_b,
											  StructAggStatePerGroupData,
											  fc_v_pergroupp,
											  FIELDNO_AGGSTATEPERGROUPDATA_TRANSVALUEISNULL,
											  "transnull");

						LLVMBuildCondBr(fc_b,
										LLVMBuildICmp(fc_b, LLVMIntEQ, fc_v_transnull,
													  l_sbool_const(1), ""),
										fc_opblocks[fc_opno + 1],
										fc_b_strictpass);

						LLVMPositionBuilderAtEnd(fc_b, fc_b_strictpass);
					}


					fc_v_fcinfo = l_ptr_const(fcinfo,
										   l_ptr(StructFunctionCallInfoData));
					fc_v_aggcontext = l_ptr_const(fc_op->d.agg_trans.aggcontext,
											   l_ptr(StructExprContext));

					fc_v_current_setp =
						l_struct_gep(fc_b,
									 StructAggState,
									 fc_v_aggstatep,
									 FIELDNO_AGGSTATE_CURRENT_SET,
									 "aggstate.current_set");
					fc_v_curaggcontext =
						l_struct_gep(fc_b,
									 StructAggState,
									 fc_v_aggstatep,
									 FIELDNO_AGGSTATE_CURAGGCONTEXT,
									 "aggstate.curaggcontext");
					fc_v_current_pertransp =
						l_struct_gep(fc_b,
									 StructAggState,
									 fc_v_aggstatep,
									 FIELDNO_AGGSTATE_CURPERTRANS,
									 "aggstate.curpertrans");

					/* 设置 aggstate 全局变量 */
					LLVMBuildStore(fc_b, fc_v_aggcontext, fc_v_curaggcontext);
					LLVMBuildStore(fc_b, l_int32_const(fc_lc, fc_op->d.agg_trans.setno),
								   fc_v_current_setp);
					LLVMBuildStore(fc_b, fc_v_pertransp, fc_v_current_pertransp);

					/* 在每个元组上下文中调用转换函数 */
					fc_v_tmpcontext =
						l_ptr_const(fc_aggstate->tmpcontext->ecxt_per_tuple_memory,
									l_ptr(StructMemoryContextData));
					fc_v_oldcontext = l_mcxt_switch(fc_mod, fc_b, fc_v_tmpcontext);

					/* 将 transvalue 存储在 fcinfo->args[0] 中 */
					fc_v_transvaluep =
						l_struct_gep(fc_b,
									 StructAggStatePerGroupData,
									 fc_v_pergroupp,
									 FIELDNO_AGGSTATEPERGROUPDATA_TRANSVALUE,
									 "transvalue");
					fc_v_transnullp =
						l_struct_gep(fc_b,
									 StructAggStatePerGroupData,
									 fc_v_pergroupp,
									 FIELDNO_AGGSTATEPERGROUPDATA_TRANSVALUEISNULL,
									 "transnullp");
					LLVMBuildStore(fc_b,
								   l_load(fc_b,
										  TypeSizeT,
										  fc_v_transvaluep,
										  "transvalue"),
								   l_funcvaluep(fc_b, fc_v_fcinfo, 0));
					LLVMBuildStore(fc_b,
								   l_load(fc_b, TypeStorageBool, fc_v_transnullp, "transnull"),
								   l_funcnullp(fc_b, fc_v_fcinfo, 0));

					/* 并调用转换函数 */
					fc_v_retval = fc_BuildV1Call(fc_context, fc_b, fc_mod, fcinfo,
										   &fc_v_fcinfo_isnull);

					/*
					 * 对于按引用传递的数据类型，必须将新值复制到
					 * aggcontext 中，并释放先前的 transValue。但是如果
					 * transfn 返回了它的第一个输入的指针，我们就
					 * 不需要做任何事情。另外，如果 transfn 返回了一个
					 * 指向已经是 aggcontext 子对象的 R/W 扩展对象的指针，
					 * 则假设我们可以在不复制的情况下采用该值。
					 */
					if (fc_opcode == EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYREF ||
						fc_opcode == EEOP_AGG_PLAIN_TRANS_STRICT_BYREF ||
						fc_opcode == EEOP_AGG_PLAIN_TRANS_BYREF)
					{
						LLVMBasicBlockRef fc_b_call;
						LLVMBasicBlockRef fc_b_nocall;
						LLVMValueRef fc_v_fn;
						LLVMValueRef fc_v_transvalue;
						LLVMValueRef fc_v_transnull;
						LLVMValueRef fc_v_newval;
						LLVMValueRef fc_params[6];

						fc_b_call = l_bb_before_v(fc_opblocks[fc_opno + 1],
											   "op.%d.transcall", fc_opno);
						fc_b_nocall = l_bb_before_v(fc_opblocks[fc_opno + 1],
												 "op.%d.transnocall", fc_opno);

						fc_v_transvalue = l_load(fc_b, TypeSizeT, fc_v_transvaluep, "");
						fc_v_transnull = l_load(fc_b, TypeStorageBool, fc_v_transnullp, "");

						/*
						 * DatumGetPointer(newVal) !=
						 * DatumGetPointer(pergroup->transValue))
						 */
						LLVMBuildCondBr(fc_b,
										LLVMBuildICmp(fc_b, LLVMIntEQ,
													  fc_v_transvalue,
													  fc_v_retval, ""),
										fc_b_nocall, fc_b_call);

						/* 返回的 datum 不是传入的 datum，重新归属 */
						LLVMPositionBuilderAtEnd(fc_b, fc_b_call);

						fc_params[0] = fc_v_aggstatep;
						fc_params[1] = fc_v_pertransp;
						fc_params[2] = fc_v_retval;
						fc_params[3] = LLVMBuildTrunc(fc_b, fc_v_fcinfo_isnull,
												   TypeParamBool, "");
						fc_params[4] = fc_v_transvalue;
						fc_params[5] = LLVMBuildTrunc(fc_b, fc_v_transnull,
												   TypeParamBool, "");

						fc_v_fn = llvm_pg_func(fc_mod, "ExecAggTransReparent");
						fc_v_newval =
							l_call(fc_b,
								   LLVMGetFunctionType(fc_v_fn),
								   fc_v_fn,
								   fc_params, lengthof(fc_params),
								   "");

						/* 存储 trans 值 */
						LLVMBuildStore(fc_b, fc_v_newval, fc_v_transvaluep);
						LLVMBuildStore(fc_b, fc_v_fcinfo_isnull, fc_v_transnullp);

						l_mcxt_switch(fc_mod, fc_b, fc_v_oldcontext);
						LLVMBuildBr(fc_b, fc_opblocks[fc_opno + 1]);

						/* 返回的 datum 是传入的 datum，无需重新归属 */
						LLVMPositionBuilderAtEnd(fc_b, fc_b_nocall);
					}

					/* 存储 trans 值 */
					LLVMBuildStore(fc_b, fc_v_retval, fc_v_transvaluep);
					LLVMBuildStore(fc_b, fc_v_fcinfo_isnull, fc_v_transnullp);

					l_mcxt_switch(fc_mod, fc_b, fc_v_oldcontext);

					LLVMBuildBr(fc_b, fc_opblocks[fc_opno + 1]);
					break;
				}

			case EEOP_AGG_ORDERED_TRANS_DATUM:
				build_EvalXFunc(fc_b, fc_mod, "ExecEvalAggOrderedTransDatum",
								fc_v_state, fc_op, fc_v_econtext);
				LLVMBuildBr(fc_b, fc_opblocks[fc_opno + 1]);
				break;

			case EEOP_AGG_ORDERED_TRANS_TUPLE:
				build_EvalXFunc(fc_b, fc_mod, "ExecEvalAggOrderedTransTuple",
								fc_v_state, fc_op, fc_v_econtext);
				LLVMBuildBr(fc_b, fc_opblocks[fc_opno + 1]);
				break;

			case EEOP_LAST:
				Assert(false);
				break;
		}
	}

	LLVMDisposeBuilder(fc_b);

	/*
	 * 不要立即发出函数，而是第一次真正评估表达式时发出。这将允许
	 * 一起发出很多函数，避免重复的 llvm 和内存重新映射开销。
	 */
	{

		CompiledExprState *fc_cstate = palloc0(sizeof(CompiledExprState));

		fc_cstate->context = fc_context;
		fc_cstate->funcname = fc_funcname;

		fc_state->evalfunc = fc_ExecRunCompiledExpr;
		fc_state->evalfunc_private = fc_cstate;
	}

	llvm_leave_fatal_on_oom();

	INSTR_TIME_SET_CURRENT(fc_endtime);
	INSTR_TIME_ACCUM_DIFF(fc_context->base.instr.generation_counter,
						  fc_endtime, fc_starttime);

	return true;
}

/*
 * 运行编译的表达式。
 *
 * 这将仅在第一次调用 JIT 的表达式时调用。我们
 * 首先确保表达式仍然是最新的，然后获取指向
 * 发出的函数的指针。后者可以是触发
 * 优化和发出所有生成函数的第一件事。
 */
static Datum fc_ExecRunCompiledExpr(ExprState *fc_state, ExprContext *fc_econtext, bool *fc_isNull)
{
	CompiledExprState *fc_cstate = fc_state->evalfunc_private;
	ExprStateEvalFunc fc_func;

	CheckExprStillValid(fc_state, fc_econtext);

	llvm_enter_fatal_on_oom();
	fc_func = (ExprStateEvalFunc) llvm_get_function(fc_cstate->context,
												 fc_cstate->funcname);
	llvm_leave_fatal_on_oom();
	Assert(fc_func);

	/* 通过此函数消除未来调用的间接性 */
	fc_state->evalfunc = fc_func;

	return fc_func(fc_state, fc_econtext, fc_isNull);
}

static LLVMValueRef fc_BuildV1Call(LLVMJitContext *fc_context, LLVMBuilderRef fc_b,
			LLVMModuleRef fc_mod, FunctionCallInfo fcinfo,
			LLVMValueRef *fc_v_fcinfo_isnull)
{
	LLVMContextRef fc_lc;
	LLVMValueRef fc_v_fn;
	LLVMValueRef fc_v_fcinfo_isnullp;
	LLVMValueRef fc_v_retval;
	LLVMValueRef fc_v_fcinfo;

	fc_lc = LLVMGetModuleContext(fc_mod);

	fc_v_fn = llvm_function_reference(fc_context, fc_b, fc_mod, fcinfo);

	fc_v_fcinfo = l_ptr_const(fcinfo, l_ptr(StructFunctionCallInfoData));
	fc_v_fcinfo_isnullp = l_struct_gep(fc_b,
									StructFunctionCallInfoData,
									fc_v_fcinfo,
									FIELDNO_FUNCTIONCALLINFODATA_ISNULL,
									"v_fcinfo_isnull");
	LLVMBuildStore(fc_b, l_sbool_const(0), fc_v_fcinfo_isnullp);

	fc_v_retval = l_call(fc_b, LLVMGetFunctionType(AttributeTemplate), fc_v_fn, &fc_v_fcinfo, 1, "funccall");

	if (fc_v_fcinfo_isnull)
		*fc_v_fcinfo_isnull = l_load(fc_b, TypeStorageBool, fc_v_fcinfo_isnullp, "");

	/*
	 * 添加生命周期结束注释，表明对内存的写入不必
	 * 保留（对于内联潜力很重要）。
	 */
	{
		LLVMValueRef fc_v_lifetime = fc_create_LifetimeEnd(fc_mod);
		LLVMValueRef fc_params[2];

		fc_params[0] = l_int64_const(fc_lc, sizeof(NullableDatum) * fcinfo->nargs);
		fc_params[1] = l_ptr_const(fcinfo->args, l_ptr(LLVMInt8TypeInContext(fc_lc)));
		l_call(fc_b, LLVMGetFunctionType(fc_v_lifetime), fc_v_lifetime, fc_params, lengthof(fc_params), "");

		fc_params[0] = l_int64_const(fc_lc, sizeof(fcinfo->isnull));
		fc_params[1] = l_ptr_const(&fcinfo->isnull, l_ptr(LLVMInt8TypeInContext(fc_lc)));
		l_call(fc_b, LLVMGetFunctionType(fc_v_lifetime), fc_v_lifetime, fc_params, lengthof(fc_params), "");
	}

	return fc_v_retval;
}

/*
 * 通过调用函数 funcname 实现一个表达式步骤。
 */
static LLVMValueRef fc_build_EvalXFuncInt(LLVMBuilderRef fc_b, LLVMModuleRef fc_mod, const char *fc_funcname,
				   LLVMValueRef fc_v_state, ExprEvalStep *fc_op,
				   int fc_nargs, LLVMValueRef *fc_v_args)
{
	LLVMValueRef fc_v_fn = llvm_pg_func(fc_mod, fc_funcname);
	LLVMValueRef *fc_params;
	int			fc_argno = 0;
	LLVMValueRef fc_v_ret;

	/* 便宜的预检查，因为 llvm 只是断言 */
	if (LLVMCountParams(fc_v_fn) != (fc_nargs + 2))
		elog(ERROR, "parameter mismatch: %s expects %d passed %d",
			 fc_funcname, LLVMCountParams(fc_v_fn), fc_nargs + 2);

	fc_params = palloc(sizeof(LLVMValueRef) * (2 + fc_nargs));

	fc_params[fc_argno++] = fc_v_state;
	fc_params[fc_argno++] = l_ptr_const(fc_op, l_ptr(StructExprEvalStep));

	for (int fc_i = 0; fc_i < fc_nargs; fc_i++)
		fc_params[fc_argno++] = fc_v_args[fc_i];

	fc_v_ret = l_call(fc_b, LLVMGetFunctionType(fc_v_fn), fc_v_fn, fc_params, fc_argno, "");

	pfree(fc_params);

	return fc_v_ret;
}

static LLVMValueRef fc_create_LifetimeEnd(LLVMModuleRef fc_mod)
{
	LLVMTypeRef fc_sig;
	LLVMValueRef fc_fn;
	LLVMTypeRef fc_param_types[2];
	LLVMContextRef fc_lc;

	/* LLVM 5+ 有一个可变参数指针参数 */
#if LLVM_VERSION_MAJOR < 5
	const char *nm = "llvm.lifetime.end";
#else
	const char *fc_nm = "llvm.lifetime.end.p0i8";
#endif

	fc_fn = LLVMGetNamedFunction(fc_mod, fc_nm);
	if (fc_fn)
		return fc_fn;

	fc_lc = LLVMGetModuleContext(fc_mod);
	fc_param_types[0] = LLVMInt64TypeInContext(fc_lc);
	fc_param_types[1] = l_ptr(LLVMInt8TypeInContext(fc_lc));

	fc_sig = LLVMFunctionType(LLVMVoidTypeInContext(fc_lc), fc_param_types,
						   lengthof(fc_param_types), false);
	fc_fn = LLVMAddFunction(fc_mod, fc_nm, fc_sig);

	LLVMSetFunctionCallConv(fc_fn, LLVMCCallConv);

	Assert(LLVMGetIntrinsicID(fc_fn));

	return fc_fn;
}
